<div dir="ltr"><div dir="ltr"><div dir="ltr">Спасибо за развернутый ответ и патч.<div><br></div><div>Мы модифицировали патч, добавив логику перебора IP исходящих соединений. В нашем случае нам достаточно 4х IP, т.е.:</div><div><br></div><div><div>proxy_bind      10.10.0.1 10.10.0.2 10.10.0.3 10.10.0.4;</div></div><div><br></div><div>Вроде работает пока, балансируя соединения с 4 IP поровну.</div><div><br></div><div>Патч с модификацией:</div><div><br></div><div><div>diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c</div><div>index 1c86e54..da55a11 100644</div><div>--- a/src/mail/ngx_mail_proxy_module.c</div><div>+++ b/src/mail/ngx_mail_proxy_module.c</div><div>@@ -13,11 +13,14 @@</div><div> </div><div> </div><div> typedef struct {</div><div>-    ngx_flag_t  enable;</div><div>-    ngx_flag_t  pass_error_message;</div><div>-    ngx_flag_t  xclient;</div><div>-    size_t      buffer_size;</div><div>-    ngx_msec_t  timeout;</div><div>+    ngx_flag_t   enable;</div><div>+    ngx_flag_t   pass_error_message;</div><div>+    ngx_flag_t   xclient;</div><div>+    size_t       buffer_size;</div><div>+    ngx_msec_t   timeout;</div><div>+    ngx_addr_t  *local;</div><div>+    size_t       local_size;</div><div>+    size_t       local_index;</div><div> } ngx_mail_proxy_conf_t;</div><div> </div><div> </div><div>@@ -35,6 +38,8 @@ static void ngx_mail_proxy_close_session(ngx_mail_session_t *s);</div><div> static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);</div><div> static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,</div><div>     void *child);</div><div>+static char *ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,</div><div>+    void *conf);</div><div> </div><div> </div><div> static ngx_command_t  ngx_mail_proxy_commands[] = {</div><div>@@ -60,6 +65,13 @@ static ngx_command_t  ngx_mail_proxy_commands[] = {</div><div>       offsetof(ngx_mail_proxy_conf_t, timeout),</div><div>       NULL },</div><div> </div><div>+    { ngx_string("proxy_bind"),</div><div>+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1234|NGX_CONF_TAKE5|NGX_CONF_TAKE6|NGX_CONF_TAKE7,</div><div>+      ngx_mail_proxy_bind,</div><div>+      NGX_MAIL_SRV_CONF_OFFSET,</div><div>+      0,</div><div>+      NULL },</div><div>+</div><div>     { ngx_string("proxy_pass_error_message"),</div><div>       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,</div><div>       ngx_conf_set_flag_slot,</div><div>@@ -118,6 +130,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)</div><div> </div><div>     s->connection->log->action = "connecting to upstream";</div><div> </div><div>+    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);</div><div>     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);</div><div> </div><div>     p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));</div><div>@@ -135,6 +148,16 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)</div><div>     p->upstream.log = s->connection->log;</div><div>     p->upstream.log_error = NGX_ERROR_ERR;</div><div> </div><div>+    if (pcf->local) {</div><div>+        p->upstream.local = pcf->local + pcf->local_index;</div><div>+</div><div>+        if (pcf->local_size > 1</div><div>+                && ++pcf->local_index >= pcf->local_size) {</div><div>+            /* wrap around */</div><div>+            pcf->local_index = 0;</div><div>+        }</div><div>+    }</div><div>+</div><div>     rc = ngx_event_connect_peer(&p->upstream);</div><div> </div><div>     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {</div><div>@@ -150,8 +173,6 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer)</div><div>     s->connection->read->handler = ngx_mail_proxy_block_read;</div><div>     p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;</div><div> </div><div>-    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);</div><div>-</div><div>     s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,</div><div>                                            pcf->buffer_size);</div><div>     if (s->proxy->buffer == NULL) {</div><div>@@ -1104,6 +1125,9 @@ ngx_mail_proxy_create_conf(ngx_conf_t *cf)</div><div>     pcf->xclient = NGX_CONF_UNSET;</div><div>     pcf->buffer_size = NGX_CONF_UNSET_SIZE;</div><div>     pcf->timeout = NGX_CONF_UNSET_MSEC;</div><div>+    pcf->local = NGX_CONF_UNSET_PTR;</div><div>+    pcf->local_size = NGX_CONF_UNSET_SIZE;</div><div>+    pcf->local_index = NGX_CONF_UNSET_SIZE;</div><div> </div><div>     return pcf;</div><div> }</div><div>@@ -1121,6 +1145,57 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child)</div><div>     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,</div><div>                               (size_t) ngx_pagesize);</div><div>     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);</div><div>+    ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);</div><div>+    ngx_conf_merge_size_value(conf->local_size, prev->local_size, 0);</div><div>+    ngx_conf_merge_size_value(conf->local_index, prev->local_index, 0);</div><div>+</div><div>+    return NGX_CONF_OK;</div><div>+}</div><div>+</div><div>+static char *</div><div>+ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</div><div>+{</div><div>+    ngx_mail_proxy_conf_t  *pcf = conf;</div><div>+    size_t                  i;</div><div>+</div><div>+    ngx_int_t   rc;</div><div>+    ngx_str_t  *value;</div><div>+</div><div>+    if (pcf->local != NGX_CONF_UNSET_PTR) {</div><div>+        return "is duplicate";</div><div>+    }</div><div>+</div><div>+    value = cf->args->elts;</div><div>+</div><div>+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) {</div><div>+        pcf->local = NULL;</div><div>+        return NGX_CONF_OK;</div><div>+    }</div><div>+</div><div>+    pcf->local = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(ngx_addr_t));</div><div>+    if (pcf->local == NULL) {</div><div>+        return NGX_CONF_ERROR;</div><div>+    }</div><div>+</div><div>+    for (i = 0; i < (cf->args->nelts - 1); ++i) {</div><div>+        rc = ngx_parse_addr_port(cf->pool, pcf->local + i, value[i + 1].data,</div><div>+                                 value[i + 1].len);</div><div>+</div><div>+        switch (rc) {</div><div>+        case NGX_OK:</div><div>+            pcf->local[i].name = value[i + 1];</div><div>+            break;</div><div>+</div><div>+        case NGX_DECLINED:</div><div>+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</div><div>+                               "invalid address \"%V\"", &value[1 + 1]);</div><div>+            /* fall through */</div><div>+</div><div>+        default:</div><div>+            return NGX_CONF_ERROR;</div><div>+        }</div><div>+    }</div><div> </div><div>+    pcf->local_size = (cf->args->nelts - 1);</div><div>     return NGX_CONF_OK;</div><div> }</div></div><div><br></div></div></div></div><br><div class="gmail_quote"><div dir="ltr">пн, 14 янв. 2019 г. в 21:51, Maxim Dounin <<a href="mailto:mdounin@mdounin.ru">mdounin@mdounin.ru</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hello!<br>
<br>
On Mon, Jan 14, 2019 at 06:02:46PM +0200, Dmitriy M. wrote:<br>
<br>
> Возможно, не нашел в документации, но есть ли возможность указать от какого<br>
> исходящего (локального) IP будет сделать запрос, если это запрос от mail<br>
> модуля?<br>
<br>
Нет, сейчас mail-модуль bind не умеет.<br>
<br>
> Речь идет об аналоге proxy_bind из модулей http_proxy/stream_proxy<br>
> <a href="http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_bind" rel="noreferrer" target="_blank">http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_bind</a> . С их<br>
> помощью мы успешно решаем проблему нехватки локальных портов при большом<br>
> кол-ве исходящих соединений работая с HTTP.<br>
> Хотелось бы найти аналог и в mail модуле, т.к. похоже начинает проявляться<br>
> та же проблема нехватки локальных портов на почтовом прокси-сервере с<br>
> установленным тут nginx и модулем mail, но как обойти её без создания<br>
> дополнительных контейнеров (что бы исходящие IP были разные), пока не<br>
> придумал (тюнинги системы выполнены, расширен диапазон разрешенных портов и<br>
> пр.).<br>
<br>
Кажется, в случае mail могут иметь смысл два возможных подхода: <br>
явная директива proxy_bind (со статически заданным значением, ибо <br>
переменных в mail нет), либо же заголовок ответа от auth-скрипта <br>
Auth-Bind (аналогично Auth-Server/Auth-Port, задающих собственно <br>
адрес проксирования).<br>
<br>
Патч, добавляющий директиву proxy_bind:<br>
<br>
# HG changeset patch<br>
# User Maxim Dounin <<a href="mailto:mdounin@mdounin.ru" target="_blank">mdounin@mdounin.ru</a>><br>
# Date 1547495341 -10800<br>
#      Mon Jan 14 22:49:01 2019 +0300<br>
# Node ID 271bd1fa164251de128cdc35dc1295ceaaa06a30<br>
# Parent  6d15e452fa2eaf19408e24a0d0fcc3a31344a289<br>
Mail: proxy_bind.<br>
<br>
diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c<br>
--- a/src/mail/ngx_mail_proxy_module.c<br>
+++ b/src/mail/ngx_mail_proxy_module.c<br>
@@ -13,11 +13,12 @@<br>
<br>
<br>
 typedef struct {<br>
-    ngx_flag_t  enable;<br>
-    ngx_flag_t  pass_error_message;<br>
-    ngx_flag_t  xclient;<br>
-    size_t      buffer_size;<br>
-    ngx_msec_t  timeout;<br>
+    ngx_flag_t   enable;<br>
+    ngx_flag_t   pass_error_message;<br>
+    ngx_flag_t   xclient;<br>
+    size_t       buffer_size;<br>
+    ngx_msec_t   timeout;<br>
+    ngx_addr_t  *local;<br>
 } ngx_mail_proxy_conf_t;<br>
<br>
<br>
@@ -35,6 +36,8 @@ static void ngx_mail_proxy_close_session<br>
 static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);<br>
 static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,<br>
     void *child);<br>
+static char *ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,<br>
+    void *conf);<br>
<br>
<br>
 static ngx_command_t  ngx_mail_proxy_commands[] = {<br>
@@ -60,6 +63,13 @@ static ngx_command_t  ngx_mail_proxy_com<br>
       offsetof(ngx_mail_proxy_conf_t, timeout),<br>
       NULL },<br>
<br>
+    { ngx_string("proxy_bind"),<br>
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,<br>
+      ngx_mail_proxy_bind,<br>
+      NGX_MAIL_SRV_CONF_OFFSET,<br>
+      0,<br>
+      NULL },<br>
+<br>
     { ngx_string("proxy_pass_error_message"),<br>
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,<br>
       ngx_conf_set_flag_slot,<br>
@@ -118,6 +128,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *<br>
<br>
     s->connection->log->action = "connecting to upstream";<br>
<br>
+    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);<br>
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);<br>
<br>
     p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));<br>
@@ -134,6 +145,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *<br>
     p->upstream.get = ngx_event_get_peer;<br>
     p->upstream.log = s->connection->log;<br>
     p->upstream.log_error = NGX_ERROR_ERR;<br>
+    p->upstream.local = pcf->local;<br>
<br>
     rc = ngx_event_connect_peer(&p->upstream);<br>
<br>
@@ -150,8 +162,6 @@ ngx_mail_proxy_init(ngx_mail_session_t *<br>
     s->connection->read->handler = ngx_mail_proxy_block_read;<br>
     p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;<br>
<br>
-    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);<br>
-<br>
     s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,<br>
                                            pcf->buffer_size);<br>
     if (s->proxy->buffer == NULL) {<br>
@@ -1104,6 +1114,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c<br>
     pcf->xclient = NGX_CONF_UNSET;<br>
     pcf->buffer_size = NGX_CONF_UNSET_SIZE;<br>
     pcf->timeout = NGX_CONF_UNSET_MSEC;<br>
+    pcf->local = NGX_CONF_UNSET_PTR;<br>
<br>
     return pcf;<br>
 }<br>
@@ -1121,6 +1132,52 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf<br>
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,<br>
                               (size_t) ngx_pagesize);<br>
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);<br>
+    ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);<br>
<br>
     return NGX_CONF_OK;<br>
 }<br>
+<br>
+<br>
+static char *<br>
+ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)<br>
+{<br>
+    ngx_mail_proxy_conf_t  *pcf = conf;<br>
+<br>
+    ngx_int_t   rc;<br>
+    ngx_str_t  *value;<br>
+<br>
+    if (pcf->local != NGX_CONF_UNSET_PTR) {<br>
+        return "is duplicate";<br>
+    }<br>
+<br>
+    value = cf->args->elts;<br>
+<br>
+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) {<br>
+        pcf->local = NULL;<br>
+        return NGX_CONF_OK;<br>
+    }<br>
+<br>
+    pcf->local = ngx_palloc(cf->pool, sizeof(ngx_addr_t));<br>
+    if (pcf->local == NULL) {<br>
+        return NGX_CONF_ERROR;<br>
+    }<br>
+<br>
+    rc = ngx_parse_addr_port(cf->pool, pcf->local, value[1].data,<br>
+                             value[1].len);<br>
+<br>
+    switch (rc) {<br>
+    case NGX_OK:<br>
+        pcf->local->name = value[1];<br>
+        break;<br>
+<br>
+    case NGX_DECLINED:<br>
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>
+                           "invalid address \"%V\"", &value[1]);<br>
+        /* fall through */<br>
+<br>
+    default:<br>
+        return NGX_CONF_ERROR;<br>
+    }<br>
+<br>
+    return NGX_CONF_OK;<br>
+}<br>
<br>
<br>
-- <br>
Maxim Dounin<br>
<a href="http://mdounin.ru/" rel="noreferrer" target="_blank">http://mdounin.ru/</a><br>
_______________________________________________<br>
nginx-ru mailing list<br>
<a href="mailto:nginx-ru@nginx.org" target="_blank">nginx-ru@nginx.org</a><br>
<a href="http://mailman.nginx.org/mailman/listinfo/nginx-ru" rel="noreferrer" target="_blank">http://mailman.nginx.org/mailman/listinfo/nginx-ru</a></blockquote></div>