src/mail/ngx_mail_proxy_module.c - nginx-1.31.4 nginx/ @ 8d9666701

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_event_connect.h>
  9. #include <ngx_mail.h>


  10. typedef struct {
  11.     ngx_flag_t  enable;
  12.     ngx_flag_t  pass_error_message;
  13.     ngx_flag_t  xclient;
  14.     ngx_flag_t  smtp_auth;
  15.     ngx_uint_t  proxy_protocol;
  16.     size_t      buffer_size;
  17.     ngx_msec_t  timeout;
  18. } ngx_mail_proxy_conf_t;


  19. static void ngx_mail_proxy_block_read(ngx_event_t *rev);
  20. static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
  21. static void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
  22. static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
  23. static void ngx_mail_proxy_write_handler(ngx_event_t *wev);
  24. static ngx_int_t ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s);
  25. static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
  26.     ngx_uint_t state);
  27. static void ngx_mail_proxy_handler(ngx_event_t *ev);
  28. static void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s);
  29. static void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s);
  30. static void ngx_mail_proxy_close_session(ngx_mail_session_t *s);
  31. static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
  32. static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
  33.     void *child);


  34. static ngx_conf_enum_t  ngx_mail_proxy_protocol_versions[] = {
  35.     { ngx_string("off"), 0 },
  36.     { ngx_string("on"), 1 },
  37.     { ngx_string("v2"), 2 },
  38.     { ngx_null_string, 0 }
  39. };


  40. static ngx_command_t  ngx_mail_proxy_commands[] = {

  41.     { ngx_string("proxy"),
  42.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
  43.       ngx_conf_set_flag_slot,
  44.       NGX_MAIL_SRV_CONF_OFFSET,
  45.       offsetof(ngx_mail_proxy_conf_t, enable),
  46.       NULL },

  47.     { ngx_string("proxy_buffer"),
  48.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  49.       ngx_conf_set_size_slot,
  50.       NGX_MAIL_SRV_CONF_OFFSET,
  51.       offsetof(ngx_mail_proxy_conf_t, buffer_size),
  52.       NULL },

  53.     { ngx_string("proxy_timeout"),
  54.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  55.       ngx_conf_set_msec_slot,
  56.       NGX_MAIL_SRV_CONF_OFFSET,
  57.       offsetof(ngx_mail_proxy_conf_t, timeout),
  58.       NULL },

  59.     { ngx_string("proxy_pass_error_message"),
  60.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
  61.       ngx_conf_set_flag_slot,
  62.       NGX_MAIL_SRV_CONF_OFFSET,
  63.       offsetof(ngx_mail_proxy_conf_t, pass_error_message),
  64.       NULL },

  65.     { ngx_string("xclient"),
  66.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
  67.       ngx_conf_set_flag_slot,
  68.       NGX_MAIL_SRV_CONF_OFFSET,
  69.       offsetof(ngx_mail_proxy_conf_t, xclient),
  70.       NULL },

  71.     { ngx_string("proxy_smtp_auth"),
  72.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
  73.       ngx_conf_set_flag_slot,
  74.       NGX_MAIL_SRV_CONF_OFFSET,
  75.       offsetof(ngx_mail_proxy_conf_t, smtp_auth),
  76.       NULL },

  77.     { ngx_string("proxy_protocol"),
  78.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  79.       ngx_conf_set_enum_slot,
  80.       NGX_MAIL_SRV_CONF_OFFSET,
  81.       offsetof(ngx_mail_proxy_conf_t, proxy_protocol),
  82.       &ngx_mail_proxy_protocol_versions },

  83.       ngx_null_command
  84. };


  85. static ngx_mail_module_t  ngx_mail_proxy_module_ctx = {
  86.     NULL,                                  /* protocol */

  87.     NULL,                                  /* create main configuration */
  88.     NULL,                                  /* init main configuration */

  89.     ngx_mail_proxy_create_conf,            /* create server configuration */
  90.     ngx_mail_proxy_merge_conf              /* merge server configuration */
  91. };


  92. ngx_module_t  ngx_mail_proxy_module = {
  93.     NGX_MODULE_V1,
  94.     &ngx_mail_proxy_module_ctx,            /* module context */
  95.     ngx_mail_proxy_commands,               /* module directives */
  96.     NGX_MAIL_MODULE,                       /* module type */
  97.     NULL,                                  /* init master */
  98.     NULL,                                  /* init module */
  99.     NULL,                                  /* init process */
  100.     NULL,                                  /* init thread */
  101.     NULL,                                  /* exit thread */
  102.     NULL,                                  /* exit process */
  103.     NULL,                                  /* exit master */
  104.     NGX_MODULE_V1_PADDING
  105. };


  106. static u_char  smtp_auth_ok[] = "235 2.0.0 OK" CRLF;


  107. void
  108. ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)
  109. {
  110.     ngx_int_t                  rc;
  111.     ngx_mail_proxy_ctx_t      *p;
  112.     ngx_mail_proxy_conf_t     *pcf;
  113.     ngx_mail_core_srv_conf_t  *cscf;

  114.     s->connection->log->action = "connecting to upstream";

  115.     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  116.     p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));
  117.     if (p == NULL) {
  118.         ngx_mail_session_internal_server_error(s);
  119.         return;
  120.     }

  121.     s->proxy = p;

  122.     p->upstream.sockaddr = peer->sockaddr;
  123.     p->upstream.socklen = peer->socklen;
  124.     p->upstream.name = &peer->name;
  125.     p->upstream.get = ngx_event_get_peer;
  126.     p->upstream.log = s->connection->log;
  127.     p->upstream.log_error = NGX_ERROR_ERR;

  128.     rc = ngx_event_connect_peer(&p->upstream);

  129.     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
  130.         ngx_mail_proxy_internal_server_error(s);
  131.         return;
  132.     }

  133.     ngx_add_timer(p->upstream.connection->read, cscf->timeout);

  134.     p->upstream.connection->data = s;
  135.     p->upstream.connection->pool = s->connection->pool;

  136.     s->connection->read->handler = ngx_mail_proxy_block_read;
  137.     p->upstream.connection->write->handler = ngx_mail_proxy_write_handler;

  138.     pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);

  139.     s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
  140.                                            pcf->buffer_size);
  141.     if (s->proxy->buffer == NULL) {
  142.         ngx_mail_proxy_internal_server_error(s);
  143.         return;
  144.     }

  145.     s->proxy->proxy_protocol = pcf->proxy_protocol;

  146.     s->out.len = 0;

  147.     switch (s->protocol) {

  148.     case NGX_MAIL_POP3_PROTOCOL:
  149.         p->upstream.connection->read->handler = ngx_mail_proxy_pop3_handler;
  150.         s->mail_state = ngx_pop3_start;
  151.         break;

  152.     case NGX_MAIL_IMAP_PROTOCOL:
  153.         p->upstream.connection->read->handler = ngx_mail_proxy_imap_handler;
  154.         s->mail_state = ngx_imap_start;
  155.         break;

  156.     default: /* NGX_MAIL_SMTP_PROTOCOL */
  157.         p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
  158.         s->mail_state = ngx_smtp_start;
  159.         break;
  160.     }

  161.     if (rc == NGX_AGAIN) {
  162.         return;
  163.     }

  164.     ngx_mail_proxy_write_handler(p->upstream.connection->write);
  165. }


  166. static void
  167. ngx_mail_proxy_block_read(ngx_event_t *rev)
  168. {
  169.     ngx_connection_t    *c;
  170.     ngx_mail_session_t  *s;

  171.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy block read");

  172.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  173.         c = rev->data;
  174.         s = c->data;

  175.         ngx_mail_proxy_close_session(s);
  176.     }
  177. }


  178. static void
  179. ngx_mail_proxy_pop3_handler(ngx_event_t *rev)
  180. {
  181.     u_char                 *p;
  182.     ngx_int_t               rc;
  183.     ngx_str_t               line;
  184.     ngx_connection_t       *c;
  185.     ngx_mail_session_t     *s;
  186.     ngx_mail_proxy_conf_t  *pcf;

  187.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  188.                    "mail proxy pop3 auth handler");

  189.     c = rev->data;
  190.     s = c->data;

  191.     if (rev->timedout) {
  192.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
  193.                       "upstream timed out");
  194.         c->timedout = 1;
  195.         ngx_mail_proxy_internal_server_error(s);
  196.         return;
  197.     }

  198.     if (s->proxy->proxy_protocol) {
  199.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy pop3 busy");

  200.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  201.             ngx_mail_proxy_internal_server_error(s);
  202.             return;
  203.         }

  204.         return;
  205.     }

  206.     rc = ngx_mail_proxy_read_response(s, 0);

  207.     if (rc == NGX_AGAIN) {
  208.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  209.             ngx_mail_proxy_internal_server_error(s);
  210.             return;
  211.         }

  212.         return;
  213.     }

  214.     if (rc == NGX_ERROR) {
  215.         ngx_mail_proxy_upstream_error(s);
  216.         return;
  217.     }

  218.     switch (s->mail_state) {

  219.     case ngx_pop3_start:
  220.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");

  221.         s->connection->log->action = "sending user name to upstream";

  222.         line.len = sizeof("USER ")  - 1 + s->login.len + 2;
  223.         line.data = ngx_pnalloc(c->pool, line.len);
  224.         if (line.data == NULL) {
  225.             ngx_mail_proxy_internal_server_error(s);
  226.             return;
  227.         }

  228.         p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
  229.         p = ngx_cpymem(p, s->login.data, s->login.len);
  230.         *p++ = CR; *p = LF;

  231.         s->mail_state = ngx_pop3_user;
  232.         break;

  233.     case ngx_pop3_user:
  234.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send pass");

  235.         s->connection->log->action = "sending password to upstream";

  236.         line.len = sizeof("PASS ")  - 1 + s->passwd.len + 2;
  237.         line.data = ngx_pnalloc(c->pool, line.len);
  238.         if (line.data == NULL) {
  239.             ngx_mail_proxy_internal_server_error(s);
  240.             return;
  241.         }

  242.         p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
  243.         p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
  244.         *p++ = CR; *p = LF;

  245.         s->mail_state = ngx_pop3_passwd;
  246.         break;

  247.     case ngx_pop3_passwd:
  248.         s->connection->read->handler = ngx_mail_proxy_handler;
  249.         s->connection->write->handler = ngx_mail_proxy_handler;
  250.         rev->handler = ngx_mail_proxy_handler;
  251.         c->write->handler = ngx_mail_proxy_handler;

  252.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
  253.         ngx_add_timer(s->connection->read, pcf->timeout);
  254.         ngx_del_timer(c->read);

  255.         c->log->action = NULL;
  256.         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");

  257.         if (s->buffer->pos < s->buffer->last
  258.             || s->connection->read->ready)
  259.         {
  260.             ngx_post_event(c->write, &ngx_posted_events);
  261.         }

  262.         ngx_mail_proxy_handler(s->connection->write);

  263.         return;

  264.     default:
  265. #if (NGX_SUPPRESS_WARN)
  266.         ngx_str_null(&line);
  267. #endif
  268.         break;
  269.     }

  270.     if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
  271.         /*
  272.          * we treat the incomplete sending as NGX_ERROR
  273.          * because it is very strange here
  274.          */
  275.         ngx_mail_proxy_internal_server_error(s);
  276.         return;
  277.     }

  278.     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  279.         ngx_mail_proxy_internal_server_error(s);
  280.         return;
  281.     }

  282.     s->proxy->buffer->pos = s->proxy->buffer->start;
  283.     s->proxy->buffer->last = s->proxy->buffer->start;
  284. }


  285. static void
  286. ngx_mail_proxy_imap_handler(ngx_event_t *rev)
  287. {
  288.     u_char                 *p;
  289.     ngx_int_t               rc;
  290.     ngx_str_t               line;
  291.     ngx_connection_t       *c;
  292.     ngx_mail_session_t     *s;
  293.     ngx_mail_proxy_conf_t  *pcf;

  294.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  295.                    "mail proxy imap auth handler");

  296.     c = rev->data;
  297.     s = c->data;

  298.     if (rev->timedout) {
  299.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
  300.                       "upstream timed out");
  301.         c->timedout = 1;
  302.         ngx_mail_proxy_internal_server_error(s);
  303.         return;
  304.     }

  305.     if (s->proxy->proxy_protocol) {
  306.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy imap busy");

  307.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  308.             ngx_mail_proxy_internal_server_error(s);
  309.             return;
  310.         }

  311.         return;
  312.     }

  313.     rc = ngx_mail_proxy_read_response(s, s->mail_state);

  314.     if (rc == NGX_AGAIN) {
  315.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  316.             ngx_mail_proxy_internal_server_error(s);
  317.             return;
  318.         }

  319.         return;
  320.     }

  321.     if (rc == NGX_ERROR) {
  322.         ngx_mail_proxy_upstream_error(s);
  323.         return;
  324.     }

  325.     switch (s->mail_state) {

  326.     case ngx_imap_start:
  327.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  328.                        "mail proxy send login");

  329.         s->connection->log->action = "sending LOGIN command to upstream";

  330.         line.len = s->tag.len + sizeof("LOGIN ") - 1
  331.                    + 1 + NGX_SIZE_T_LEN + 1 + 2;
  332.         line.data = ngx_pnalloc(c->pool, line.len);
  333.         if (line.data == NULL) {
  334.             ngx_mail_proxy_internal_server_error(s);
  335.             return;
  336.         }

  337.         line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
  338.                                &s->tag, s->login.len)
  339.                    - line.data;

  340.         s->mail_state = ngx_imap_login;
  341.         break;

  342.     case ngx_imap_login:
  343.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");

  344.         s->connection->log->action = "sending user name to upstream";

  345.         line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2;
  346.         line.data = ngx_pnalloc(c->pool, line.len);
  347.         if (line.data == NULL) {
  348.             ngx_mail_proxy_internal_server_error(s);
  349.             return;
  350.         }

  351.         line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF,
  352.                                &s->login, s->passwd.len)
  353.                    - line.data;

  354.         s->mail_state = ngx_imap_user;
  355.         break;

  356.     case ngx_imap_user:
  357.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  358.                        "mail proxy send passwd");

  359.         s->connection->log->action = "sending password to upstream";

  360.         line.len = s->passwd.len + 2;
  361.         line.data = ngx_pnalloc(c->pool, line.len);
  362.         if (line.data == NULL) {
  363.             ngx_mail_proxy_internal_server_error(s);
  364.             return;
  365.         }

  366.         p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len);
  367.         *p++ = CR; *p = LF;

  368.         s->mail_state = ngx_imap_passwd;
  369.         break;

  370.     case ngx_imap_passwd:
  371.         s->connection->read->handler = ngx_mail_proxy_handler;
  372.         s->connection->write->handler = ngx_mail_proxy_handler;
  373.         rev->handler = ngx_mail_proxy_handler;
  374.         c->write->handler = ngx_mail_proxy_handler;

  375.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
  376.         ngx_add_timer(s->connection->read, pcf->timeout);
  377.         ngx_del_timer(c->read);

  378.         c->log->action = NULL;
  379.         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");

  380.         if (s->buffer->pos < s->buffer->last
  381.             || s->connection->read->ready)
  382.         {
  383.             ngx_post_event(c->write, &ngx_posted_events);
  384.         }

  385.         ngx_mail_proxy_handler(s->connection->write);

  386.         return;

  387.     default:
  388. #if (NGX_SUPPRESS_WARN)
  389.         ngx_str_null(&line);
  390. #endif
  391.         break;
  392.     }

  393.     if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
  394.         /*
  395.          * we treat the incomplete sending as NGX_ERROR
  396.          * because it is very strange here
  397.          */
  398.         ngx_mail_proxy_internal_server_error(s);
  399.         return;
  400.     }

  401.     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  402.         ngx_mail_proxy_internal_server_error(s);
  403.         return;
  404.     }

  405.     s->proxy->buffer->pos = s->proxy->buffer->start;
  406.     s->proxy->buffer->last = s->proxy->buffer->start;
  407. }


  408. static void
  409. ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
  410. {
  411.     u_char                    *p;
  412.     ngx_int_t                  rc;
  413.     ngx_str_t                  line, auth, encoded;
  414.     ngx_buf_t                 *b;
  415.     uintptr_t                  n;
  416.     ngx_connection_t          *c;
  417.     ngx_mail_session_t        *s;
  418.     ngx_mail_proxy_conf_t     *pcf;
  419.     ngx_mail_core_srv_conf_t  *cscf;

  420.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  421.                    "mail proxy smtp auth handler");

  422.     c = rev->data;
  423.     s = c->data;

  424.     if (rev->timedout) {
  425.         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
  426.                       "upstream timed out");
  427.         c->timedout = 1;
  428.         ngx_mail_proxy_internal_server_error(s);
  429.         return;
  430.     }

  431.     if (s->proxy->proxy_protocol) {
  432.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy smtp busy");

  433.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  434.             ngx_mail_proxy_internal_server_error(s);
  435.             return;
  436.         }

  437.         return;
  438.     }

  439.     rc = ngx_mail_proxy_read_response(s, s->mail_state);

  440.     if (rc == NGX_AGAIN) {
  441.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  442.             ngx_mail_proxy_internal_server_error(s);
  443.             return;
  444.         }

  445.         return;
  446.     }

  447.     if (rc == NGX_ERROR) {
  448.         ngx_mail_proxy_upstream_error(s);
  449.         return;
  450.     }

  451.     switch (s->mail_state) {

  452.     case ngx_smtp_start:
  453.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send ehlo");

  454.         s->connection->log->action = "sending HELO/EHLO to upstream";

  455.         cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

  456.         line.len = sizeof("HELO ")  - 1 + cscf->server_name.len + 2;
  457.         line.data = ngx_pnalloc(c->pool, line.len);
  458.         if (line.data == NULL) {
  459.             ngx_mail_proxy_internal_server_error(s);
  460.             return;
  461.         }

  462.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);

  463.         p = ngx_cpymem(line.data,
  464.                        ((s->esmtp || pcf->xclient) ? "EHLO " : "HELO "),
  465.                        sizeof("HELO ") - 1);

  466.         p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
  467.         *p++ = CR; *p = LF;

  468.         if (pcf->xclient) {
  469.             s->mail_state = ngx_smtp_helo_xclient;

  470.         } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
  471.             s->mail_state = ngx_smtp_helo_from;

  472.         } else if (pcf->smtp_auth) {
  473.             s->mail_state = ngx_smtp_helo_auth;

  474.         } else {
  475.             s->mail_state = ngx_smtp_helo;
  476.         }

  477.         break;

  478.     case ngx_smtp_helo_xclient:
  479.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  480.                        "mail proxy send xclient");

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

  482.         line.len = sizeof("XCLIENT ADDR= LOGIN= NAME="
  483.                           CRLF) - 1
  484.                    + s->connection->addr_text.len + s->login.len + s->host.len;

  485.         n = ngx_escape_uri(NULL, s->login.data, s->login.len,
  486.                            NGX_ESCAPE_MAIL_XTEXT);
  487.         line.len += n * 2;

  488. #if (NGX_HAVE_INET6)
  489.         if (s->connection->sockaddr->sa_family == AF_INET6) {
  490.             line.len += sizeof("IPV6:") - 1;
  491.         }
  492. #endif

  493.         line.data = ngx_pnalloc(c->pool, line.len);
  494.         if (line.data == NULL) {
  495.             ngx_mail_proxy_internal_server_error(s);
  496.             return;
  497.         }

  498.         p = ngx_cpymem(line.data, "XCLIENT ADDR=", sizeof("XCLIENT ADDR=") - 1);

  499. #if (NGX_HAVE_INET6)
  500.         if (s->connection->sockaddr->sa_family == AF_INET6) {
  501.             p = ngx_cpymem(p, "IPV6:", sizeof("IPV6:") - 1);
  502.         }
  503. #endif

  504.         p = ngx_copy(p, s->connection->addr_text.data,
  505.                      s->connection->addr_text.len);

  506.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);

  507.         if (s->login.len && !pcf->smtp_auth) {
  508.             p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);

  509.             if (n == 0) {
  510.                 p = ngx_copy(p, s->login.data, s->login.len);

  511.             } else {
  512.                 p = (u_char *) ngx_escape_uri(p, s->login.data, s->login.len,
  513.                                               NGX_ESCAPE_MAIL_XTEXT);
  514.             }
  515.         }

  516.         p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1);
  517.         p = ngx_copy(p, s->host.data, s->host.len);

  518.         *p++ = CR; *p++ = LF;

  519.         line.len = p - line.data;

  520.         if (s->smtp_helo.len) {
  521.             s->mail_state = ngx_smtp_xclient_helo;

  522.         } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
  523.             s->mail_state = ngx_smtp_xclient_from;

  524.         } else if (pcf->smtp_auth) {
  525.             s->mail_state = ngx_smtp_xclient_auth;

  526.         } else {
  527.             s->mail_state = ngx_smtp_xclient;
  528.         }

  529.         break;

  530.     case ngx_smtp_xclient_helo:
  531.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  532.                        "mail proxy send client ehlo");

  533.         s->connection->log->action = "sending client HELO/EHLO to upstream";

  534.         line.len = sizeof("HELO " CRLF) - 1 + s->smtp_helo.len;

  535.         line.data = ngx_pnalloc(c->pool, line.len);
  536.         if (line.data == NULL) {
  537.             ngx_mail_proxy_internal_server_error(s);
  538.             return;
  539.         }

  540.         line.len = ngx_sprintf(line.data,
  541.                        ((s->esmtp) ? "EHLO %V" CRLF : "HELO %V" CRLF),
  542.                        &s->smtp_helo)
  543.                    - line.data;

  544.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);

  545.         if (s->auth_method == NGX_MAIL_AUTH_NONE) {
  546.             s->mail_state = ngx_smtp_helo_from;

  547.         } else if (pcf->smtp_auth) {
  548.             s->mail_state = ngx_smtp_helo_auth;

  549.         } else {
  550.             s->mail_state = ngx_smtp_helo;
  551.         }

  552.         break;

  553.     case ngx_smtp_helo_auth:
  554.     case ngx_smtp_xclient_auth:
  555.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  556.                        "mail proxy send auth");

  557.         s->connection->log->action = "sending AUTH to upstream";

  558.         if (s->passwd.data == NULL) {
  559.             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  560.                           "no password available");
  561.             ngx_mail_proxy_internal_server_error(s);
  562.             return;
  563.         }

  564.         auth.len = 1 + s->login.len + 1 + s->passwd.len;
  565.         auth.data = ngx_pnalloc(c->pool, auth.len);
  566.         if (auth.data == NULL) {
  567.             ngx_mail_proxy_internal_server_error(s);
  568.             return;
  569.         }

  570.         auth.len = ngx_sprintf(auth.data, "%Z%V%Z%V", &s->login, &s->passwd)
  571.                    - auth.data;

  572.         line.len = sizeof("AUTH PLAIN " CRLF) - 1
  573.                    + ngx_base64_encoded_length(auth.len);

  574.         line.data = ngx_pnalloc(c->pool, line.len);
  575.         if (line.data == NULL) {
  576.             ngx_mail_proxy_internal_server_error(s);
  577.             return;
  578.         }

  579.         encoded.data = ngx_cpymem(line.data, "AUTH PLAIN ",
  580.                                   sizeof("AUTH PLAIN ") - 1);

  581.         ngx_encode_base64(&encoded, &auth);

  582.         p = encoded.data + encoded.len;
  583.         *p++ = CR; *p = LF;

  584.         s->mail_state = ngx_smtp_auth_plain;

  585.         break;

  586.     case ngx_smtp_helo_from:
  587.     case ngx_smtp_xclient_from:
  588.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  589.                        "mail proxy send mail from");

  590.         s->connection->log->action = "sending MAIL FROM to upstream";

  591.         line.len = s->smtp_from.len + sizeof(CRLF) - 1;
  592.         line.data = ngx_pnalloc(c->pool, line.len);
  593.         if (line.data == NULL) {
  594.             ngx_mail_proxy_internal_server_error(s);
  595.             return;
  596.         }

  597.         p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len);
  598.         *p++ = CR; *p = LF;

  599.         s->mail_state = ngx_smtp_from;

  600.         break;

  601.     case ngx_smtp_from:
  602.         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
  603.                        "mail proxy send rcpt to");

  604.         s->connection->log->action = "sending RCPT TO to upstream";

  605.         line.len = s->smtp_to.len + sizeof(CRLF) - 1;
  606.         line.data = ngx_pnalloc(c->pool, line.len);
  607.         if (line.data == NULL) {
  608.             ngx_mail_proxy_internal_server_error(s);
  609.             return;
  610.         }

  611.         p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len);
  612.         *p++ = CR; *p = LF;

  613.         s->mail_state = ngx_smtp_to;

  614.         break;

  615.     case ngx_smtp_helo:
  616.     case ngx_smtp_xclient:
  617.     case ngx_smtp_auth_plain:
  618.     case ngx_smtp_to:

  619.         b = s->proxy->buffer;

  620.         if (s->auth_method == NGX_MAIL_AUTH_NONE) {
  621.             b->pos = b->start;

  622.         } else {
  623.             ngx_memcpy(b->start, smtp_auth_ok, sizeof(smtp_auth_ok) - 1);
  624.             b->last = b->start + sizeof(smtp_auth_ok) - 1;
  625.         }

  626.         s->connection->read->handler = ngx_mail_proxy_handler;
  627.         s->connection->write->handler = ngx_mail_proxy_handler;
  628.         rev->handler = ngx_mail_proxy_handler;
  629.         c->write->handler = ngx_mail_proxy_handler;

  630.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
  631.         ngx_add_timer(s->connection->read, pcf->timeout);
  632.         ngx_del_timer(c->read);

  633.         c->log->action = NULL;
  634.         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");

  635.         if (s->buffer->pos < s->buffer->last
  636.             || s->connection->read->ready)
  637.         {
  638.             ngx_post_event(c->write, &ngx_posted_events);
  639.         }

  640.         ngx_mail_proxy_handler(s->connection->write);

  641.         return;

  642.     default:
  643. #if (NGX_SUPPRESS_WARN)
  644.         ngx_str_null(&line);
  645. #endif
  646.         break;
  647.     }

  648.     if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
  649.         /*
  650.          * we treat the incomplete sending as NGX_ERROR
  651.          * because it is very strange here
  652.          */
  653.         ngx_mail_proxy_internal_server_error(s);
  654.         return;
  655.     }

  656.     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  657.         ngx_mail_proxy_internal_server_error(s);
  658.         return;
  659.     }

  660.     s->proxy->buffer->pos = s->proxy->buffer->start;
  661.     s->proxy->buffer->last = s->proxy->buffer->start;
  662. }


  663. static void
  664. ngx_mail_proxy_write_handler(ngx_event_t *wev)
  665. {
  666.     ngx_connection_t    *c;
  667.     ngx_mail_session_t  *s;

  668.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy write handler");

  669.     c = wev->data;
  670.     s = c->data;

  671.     if (s->proxy->proxy_protocol) {
  672.         if (ngx_mail_proxy_send_proxy_protocol(s) != NGX_OK) {
  673.             return;
  674.         }

  675.         s->proxy->proxy_protocol = 0;
  676.     }

  677.     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
  678.         ngx_mail_proxy_internal_server_error(s);
  679.         return;
  680.     }

  681.     if (c->read->ready) {
  682.         ngx_post_event(c->read, &ngx_posted_events);
  683.     }
  684. }


  685. static ngx_int_t
  686. ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s)
  687. {
  688.     u_char            *p;
  689.     size_t             size;
  690.     ssize_t            n;
  691.     ngx_connection_t  *c;
  692.     static u_char      buf[NGX_PROXY_PROTOCOL_MAX_HEADER];

  693.     s->connection->log->action = "sending PROXY protocol header to upstream";

  694.     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  695.                    "mail proxy send PROXY protocol header");

  696.     if (s->proxy->proxy_protocol == 2) {
  697.         p = ngx_proxy_protocol_v2_write(s->connection, buf,
  698.                                         buf + sizeof(buf), NULL);

  699.     } else {
  700.         p = ngx_proxy_protocol_write(s->connection, buf,
  701.                                      buf + sizeof(buf));
  702.     }

  703.     if (p == NULL) {
  704.         ngx_mail_proxy_internal_server_error(s);
  705.         return NGX_ERROR;
  706.     }

  707.     c = s->proxy->upstream.connection;

  708.     size = p - buf;

  709.     n = c->send(c, buf, size);

  710.     if (n == NGX_AGAIN) {
  711.         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
  712.             ngx_mail_proxy_internal_server_error(s);
  713.             return NGX_ERROR;
  714.         }

  715.         return NGX_AGAIN;
  716.     }

  717.     if (n == NGX_ERROR) {
  718.         ngx_mail_proxy_internal_server_error(s);
  719.         return NGX_ERROR;
  720.     }

  721.     if (n != (ssize_t) size) {

  722.         /*
  723.          * PROXY protocol specification:
  724.          * The sender must always ensure that the header
  725.          * is sent at once, so that the transport layer
  726.          * maintains atomicity along the path to the receiver.
  727.          */

  728.         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  729.                       "could not send PROXY protocol header at once");

  730.         ngx_mail_proxy_internal_server_error(s);

  731.         return NGX_ERROR;
  732.     }

  733.     return NGX_OK;
  734. }


  735. static ngx_int_t
  736. ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
  737. {
  738.     u_char                 *p, *m;
  739.     ssize_t                 n;
  740.     ngx_buf_t              *b;
  741.     ngx_mail_proxy_conf_t  *pcf;

  742.     s->connection->log->action = "reading response from upstream";

  743.     b = s->proxy->buffer;

  744.     n = s->proxy->upstream.connection->recv(s->proxy->upstream.connection,
  745.                                             b->last, b->end - b->last);

  746.     if (n == NGX_ERROR || n == 0) {
  747.         return NGX_ERROR;
  748.     }

  749.     if (n == NGX_AGAIN) {
  750.         return NGX_AGAIN;
  751.     }

  752.     b->last += n;

  753.     if (b->last - b->pos < 4) {
  754.         return NGX_AGAIN;
  755.     }

  756.     if (*(b->last - 2) != CR || *(b->last - 1) != LF) {
  757.         if (b->last == b->end) {
  758.             *(b->last - 1) = '\0';
  759.             ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  760.                           "upstream sent too long response line: \"%s\"",
  761.                           b->pos);
  762.             return NGX_ERROR;
  763.         }

  764.         return NGX_AGAIN;
  765.     }

  766.     p = b->pos;

  767.     switch (s->protocol) {

  768.     case NGX_MAIL_POP3_PROTOCOL:
  769.         if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
  770.             return NGX_OK;
  771.         }
  772.         break;

  773.     case NGX_MAIL_IMAP_PROTOCOL:
  774.         switch (state) {

  775.         case ngx_imap_start:
  776.             if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
  777.                 return NGX_OK;
  778.             }
  779.             break;

  780.         case ngx_imap_login:
  781.         case ngx_imap_user:
  782.             if (p[0] == '+') {
  783.                 return NGX_OK;
  784.             }
  785.             break;

  786.         case ngx_imap_passwd:

  787.             /*
  788.              * untagged CAPABILITY response (draft-crispin-imapv-16),
  789.              * known to be sent by SmarterMail and Gmail
  790.              */

  791.             if (p[0] == '*' && p[1] == ' ') {
  792.                 p += 2;

  793.                 while (p < b->last - 1) {
  794.                     if (p[0] == CR && p[1] == LF) {
  795.                         p += 2;
  796.                         break;
  797.                     }

  798.                     p++;
  799.                 }

  800.                 if (b->last - p < 4) {
  801.                     return NGX_AGAIN;
  802.                 }
  803.             }

  804.             if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) {
  805.                 p += s->tag.len;
  806.                 if (p[0] == 'O' && p[1] == 'K') {
  807.                     return NGX_OK;
  808.                 }
  809.             }

  810.             break;
  811.         }

  812.         break;

  813.     default: /* NGX_MAIL_SMTP_PROTOCOL */

  814.         if (p[3] == '-') {
  815.             /* multiline reply, check if we got last line */

  816.             m = b->last - (sizeof(CRLF "200" CRLF) - 1);

  817.             while (m > p) {
  818.                 if (m[0] == CR && m[1] == LF) {
  819.                     break;
  820.                 }

  821.                 m--;
  822.             }

  823.             if (m <= p || m[5] == '-') {
  824.                 return NGX_AGAIN;
  825.             }
  826.         }

  827.         switch (state) {

  828.         case ngx_smtp_start:
  829.             if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
  830.                 return NGX_OK;
  831.             }
  832.             break;

  833.         case ngx_smtp_helo:
  834.         case ngx_smtp_helo_xclient:
  835.         case ngx_smtp_helo_from:
  836.         case ngx_smtp_helo_auth:
  837.         case ngx_smtp_from:
  838.             if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
  839.                 return NGX_OK;
  840.             }
  841.             break;

  842.         case ngx_smtp_xclient:
  843.         case ngx_smtp_xclient_from:
  844.         case ngx_smtp_xclient_helo:
  845.         case ngx_smtp_xclient_auth:
  846.             if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') {
  847.                 return NGX_OK;
  848.             }
  849.             break;

  850.         case ngx_smtp_auth_plain:
  851.             if (p[0] == '2' && p[1] == '3' && p[2] == '5') {
  852.                 return NGX_OK;
  853.             }
  854.             break;

  855.         case ngx_smtp_to:
  856.             return NGX_OK;
  857.         }

  858.         break;
  859.     }

  860.     pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);

  861.     if (pcf->pass_error_message == 0) {
  862.         *(b->last - 2) = '\0';
  863.         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
  864.                       "upstream sent invalid response: \"%s\"", p);
  865.         return NGX_ERROR;
  866.     }

  867.     s->out.len = b->last - p - 2;
  868.     s->out.data = p;

  869.     ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
  870.                   "upstream sent invalid response: \"%V\"", &s->out);

  871.     s->out.len = b->last - b->pos;
  872.     s->out.data = b->pos;

  873.     return NGX_ERROR;
  874. }


  875. static void
  876. ngx_mail_proxy_handler(ngx_event_t *ev)
  877. {
  878.     char                   *action, *recv_action, *send_action;
  879.     size_t                  size;
  880.     ssize_t                 n;
  881.     ngx_buf_t              *b;
  882.     ngx_uint_t              do_write;
  883.     ngx_connection_t       *c, *src, *dst;
  884.     ngx_mail_session_t     *s;
  885.     ngx_mail_proxy_conf_t  *pcf;

  886.     c = ev->data;
  887.     s = c->data;

  888.     if (ev->timedout || c->close) {
  889.         c->log->action = "proxying";

  890.         if (c->close) {
  891.             ngx_log_error(NGX_LOG_INFO, c->log, 0, "shutdown timeout");

  892.         } else if (c == s->connection) {
  893.             ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
  894.                           "client timed out");
  895.             c->timedout = 1;

  896.         } else {
  897.             ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
  898.                           "upstream timed out");
  899.         }

  900.         ngx_mail_proxy_close_session(s);
  901.         return;
  902.     }

  903.     if (c == s->connection) {
  904.         if (ev->write) {
  905.             recv_action = "proxying and reading from upstream";
  906.             send_action = "proxying and sending to client";
  907.             src = s->proxy->upstream.connection;
  908.             dst = c;
  909.             b = s->proxy->buffer;

  910.         } else {
  911.             recv_action = "proxying and reading from client";
  912.             send_action = "proxying and sending to upstream";
  913.             src = c;
  914.             dst = s->proxy->upstream.connection;
  915.             b = s->buffer;
  916.         }

  917.     } else {
  918.         if (ev->write) {
  919.             recv_action = "proxying and reading from client";
  920.             send_action = "proxying and sending to upstream";
  921.             src = s->connection;
  922.             dst = c;
  923.             b = s->buffer;

  924.         } else {
  925.             recv_action = "proxying and reading from upstream";
  926.             send_action = "proxying and sending to client";
  927.             src = c;
  928.             dst = s->connection;
  929.             b = s->proxy->buffer;
  930.         }
  931.     }

  932.     do_write = ev->write ? 1 : 0;

  933.     ngx_log_debug3(NGX_LOG_DEBUG_MAIL, ev->log, 0,
  934.                    "mail proxy handler: %ui, #%d > #%d",
  935.                    do_write, src->fd, dst->fd);

  936.     for ( ;; ) {

  937.         if (do_write) {

  938.             size = b->last - b->pos;

  939.             if (size && dst->write->ready) {
  940.                 c->log->action = send_action;

  941.                 n = dst->send(dst, b->pos, size);

  942.                 if (n == NGX_ERROR) {
  943.                     ngx_mail_proxy_close_session(s);
  944.                     return;
  945.                 }

  946.                 if (n > 0) {
  947.                     b->pos += n;

  948.                     if (b->pos == b->last) {
  949.                         b->pos = b->start;
  950.                         b->last = b->start;
  951.                     }
  952.                 }
  953.             }
  954.         }

  955.         size = b->end - b->last;

  956.         if (size && src->read->ready) {
  957.             c->log->action = recv_action;

  958.             n = src->recv(src, b->last, size);

  959.             if (n == NGX_AGAIN || n == 0) {
  960.                 break;
  961.             }

  962.             if (n > 0) {
  963.                 do_write = 1;
  964.                 b->last += n;

  965.                 continue;
  966.             }

  967.             if (n == NGX_ERROR) {
  968.                 src->read->eof = 1;
  969.             }
  970.         }

  971.         break;
  972.     }

  973.     c->log->action = "proxying";

  974.     if ((s->connection->read->eof && s->buffer->pos == s->buffer->last)
  975.         || (s->proxy->upstream.connection->read->eof
  976.             && s->proxy->buffer->pos == s->proxy->buffer->last)
  977.         || (s->connection->read->eof
  978.             && s->proxy->upstream.connection->read->eof))
  979.     {
  980.         action = c->log->action;
  981.         c->log->action = NULL;
  982.         ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done");
  983.         c->log->action = action;

  984.         ngx_mail_proxy_close_session(s);
  985.         return;
  986.     }

  987.     if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
  988.         ngx_mail_proxy_close_session(s);
  989.         return;
  990.     }

  991.     if (ngx_handle_read_event(dst->read, 0) != NGX_OK) {
  992.         ngx_mail_proxy_close_session(s);
  993.         return;
  994.     }

  995.     if (ngx_handle_write_event(src->write, 0) != NGX_OK) {
  996.         ngx_mail_proxy_close_session(s);
  997.         return;
  998.     }

  999.     if (ngx_handle_read_event(src->read, 0) != NGX_OK) {
  1000.         ngx_mail_proxy_close_session(s);
  1001.         return;
  1002.     }

  1003.     if (c == s->connection) {
  1004.         pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
  1005.         ngx_add_timer(c->read, pcf->timeout);
  1006.     }
  1007. }


  1008. static void
  1009. ngx_mail_proxy_upstream_error(ngx_mail_session_t *s)
  1010. {
  1011.     if (s->proxy->upstream.connection) {
  1012.         ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  1013.                        "close mail proxy connection: %d",
  1014.                        s->proxy->upstream.connection->fd);

  1015.         ngx_close_connection(s->proxy->upstream.connection);
  1016.     }

  1017.     if (s->out.len == 0) {
  1018.         ngx_mail_session_internal_server_error(s);
  1019.         return;
  1020.     }

  1021.     s->quit = 1;
  1022.     ngx_mail_send(s->connection->write);
  1023. }


  1024. static void
  1025. ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s)
  1026. {
  1027.     if (s->proxy->upstream.connection) {
  1028.         ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  1029.                        "close mail proxy connection: %d",
  1030.                        s->proxy->upstream.connection->fd);

  1031.         ngx_close_connection(s->proxy->upstream.connection);
  1032.     }

  1033.     ngx_mail_session_internal_server_error(s);
  1034. }


  1035. static void
  1036. ngx_mail_proxy_close_session(ngx_mail_session_t *s)
  1037. {
  1038.     if (s->proxy->upstream.connection) {
  1039.         ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
  1040.                        "close mail proxy connection: %d",
  1041.                        s->proxy->upstream.connection->fd);

  1042.         ngx_close_connection(s->proxy->upstream.connection);
  1043.     }

  1044.     ngx_mail_close_connection(s->connection);
  1045. }


  1046. static void *
  1047. ngx_mail_proxy_create_conf(ngx_conf_t *cf)
  1048. {
  1049.     ngx_mail_proxy_conf_t  *pcf;

  1050.     pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t));
  1051.     if (pcf == NULL) {
  1052.         return NULL;
  1053.     }

  1054.     pcf->enable = NGX_CONF_UNSET;
  1055.     pcf->pass_error_message = NGX_CONF_UNSET;
  1056.     pcf->xclient = NGX_CONF_UNSET;
  1057.     pcf->smtp_auth = NGX_CONF_UNSET;
  1058.     pcf->proxy_protocol = NGX_CONF_UNSET_UINT;
  1059.     pcf->buffer_size = NGX_CONF_UNSET_SIZE;
  1060.     pcf->timeout = NGX_CONF_UNSET_MSEC;

  1061.     return pcf;
  1062. }


  1063. static char *
  1064. ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child)
  1065. {
  1066.     ngx_mail_proxy_conf_t *prev = parent;
  1067.     ngx_mail_proxy_conf_t *conf = child;

  1068.     ngx_conf_merge_value(conf->enable, prev->enable, 0);
  1069.     ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0);
  1070.     ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
  1071.     ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0);
  1072.     ngx_conf_merge_uint_value(conf->proxy_protocol, prev->proxy_protocol, 0);
  1073.     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
  1074.                               (size_t) ngx_pagesize);
  1075.     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);

  1076.     return NGX_CONF_OK;
  1077. }