Re: Возможность сделать bind() для исходящих запросов модуля mail

Dmitriy M. endo.mulo на gmail.com
Вт Янв 15 11:28:52 UTC 2019


Спасибо за развернутый ответ и патч.

Мы модифицировали патч, добавив логику перебора IP исходящих соединений. В
нашем случае нам достаточно 4х IP, т.е.:

proxy_bind      10.10.0.1 10.10.0.2 10.10.0.3 10.10.0.4;

Вроде работает пока, балансируя соединения с 4 IP поровну.

Патч с модификацией:

diff --git a/src/mail/ngx_mail_proxy_module.c
b/src/mail/ngx_mail_proxy_module.c
index 1c86e54..da55a11 100644
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -13,11 +13,14 @@


 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_flag_t   enable;
+    ngx_flag_t   pass_error_message;
+    ngx_flag_t   xclient;
+    size_t       buffer_size;
+    ngx_msec_t   timeout;
+    ngx_addr_t  *local;
+    size_t       local_size;
+    size_t       local_index;
 } ngx_mail_proxy_conf_t;


@@ -35,6 +38,8 @@ static void
ngx_mail_proxy_close_session(ngx_mail_session_t *s);
 static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
 static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
     void *child);
+static char *ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);


 static ngx_command_t  ngx_mail_proxy_commands[] = {
@@ -60,6 +65,13 @@ static ngx_command_t  ngx_mail_proxy_commands[] = {
       offsetof(ngx_mail_proxy_conf_t, timeout),
       NULL },

+    { ngx_string("proxy_bind"),
+
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1234|NGX_CONF_TAKE5|NGX_CONF_TAKE6|NGX_CONF_TAKE7,
+      ngx_mail_proxy_bind,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("proxy_pass_error_message"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -118,6 +130,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t
*peer)

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

+    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

     p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));
@@ -135,6 +148,16 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t
*peer)
     p->upstream.log = s->connection->log;
     p->upstream.log_error = NGX_ERROR_ERR;

+    if (pcf->local) {
+        p->upstream.local = pcf->local + pcf->local_index;
+
+        if (pcf->local_size > 1
+                && ++pcf->local_index >= pcf->local_size) {
+            /* wrap around */
+            pcf->local_index = 0;
+        }
+    }
+
     rc = ngx_event_connect_peer(&p->upstream);

     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
@@ -150,8 +173,6 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t
*peer)
     s->connection->read->handler = ngx_mail_proxy_block_read;
     p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;

-    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
-
     s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
                                            pcf->buffer_size);
     if (s->proxy->buffer == NULL) {
@@ -1104,6 +1125,9 @@ ngx_mail_proxy_create_conf(ngx_conf_t *cf)
     pcf->xclient = NGX_CONF_UNSET;
     pcf->buffer_size = NGX_CONF_UNSET_SIZE;
     pcf->timeout = NGX_CONF_UNSET_MSEC;
+    pcf->local = NGX_CONF_UNSET_PTR;
+    pcf->local_size = NGX_CONF_UNSET_SIZE;
+    pcf->local_index = NGX_CONF_UNSET_SIZE;

     return pcf;
 }
@@ -1121,6 +1145,57 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void
*parent, void *child)
     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);
+    ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
+    ngx_conf_merge_size_value(conf->local_size, prev->local_size, 0);
+    ngx_conf_merge_size_value(conf->local_index, prev->local_index, 0);
+
+    return NGX_CONF_OK;
+}
+
+static char *
+ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_proxy_conf_t  *pcf = conf;
+    size_t                  i;
+
+    ngx_int_t   rc;
+    ngx_str_t  *value;
+
+    if (pcf->local != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) {
+        pcf->local = NULL;
+        return NGX_CONF_OK;
+    }
+
+    pcf->local = ngx_palloc(cf->pool, (cf->args->nelts - 1) *
sizeof(ngx_addr_t));
+    if (pcf->local == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    for (i = 0; i < (cf->args->nelts - 1); ++i) {
+        rc = ngx_parse_addr_port(cf->pool, pcf->local + i, value[i +
1].data,
+                                 value[i + 1].len);
+
+        switch (rc) {
+        case NGX_OK:
+            pcf->local[i].name = value[i + 1];
+            break;
+
+        case NGX_DECLINED:
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid address \"%V\"", &value[1 + 1]);
+            /* fall through */
+
+        default:
+            return NGX_CONF_ERROR;
+        }
+    }

+    pcf->local_size = (cf->args->nelts - 1);
     return NGX_CONF_OK;
 }


пн, 14 янв. 2019 г. в 21:51, Maxim Dounin <mdounin на mdounin.ru>:

> Hello!
>
> On Mon, Jan 14, 2019 at 06:02:46PM +0200, Dmitriy M. wrote:
>
> > Возможно, не нашел в документации, но есть ли возможность указать от
> какого
> > исходящего (локального) IP будет сделать запрос, если это запрос от mail
> > модуля?
>
> Нет, сейчас mail-модуль bind не умеет.
>
> > Речь идет об аналоге proxy_bind из модулей http_proxy/stream_proxy
> > http://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_bind . С
> их
> > помощью мы успешно решаем проблему нехватки локальных портов при большом
> > кол-ве исходящих соединений работая с HTTP.
> > Хотелось бы найти аналог и в mail модуле, т.к. похоже начинает
> проявляться
> > та же проблема нехватки локальных портов на почтовом прокси-сервере с
> > установленным тут nginx и модулем mail, но как обойти её без создания
> > дополнительных контейнеров (что бы исходящие IP были разные), пока не
> > придумал (тюнинги системы выполнены, расширен диапазон разрешенных
> портов и
> > пр.).
>
> Кажется, в случае mail могут иметь смысл два возможных подхода:
> явная директива proxy_bind (со статически заданным значением, ибо
> переменных в mail нет), либо же заголовок ответа от auth-скрипта
> Auth-Bind (аналогично Auth-Server/Auth-Port, задающих собственно
> адрес проксирования).
>
> Патч, добавляющий директиву proxy_bind:
>
> # HG changeset patch
> # User Maxim Dounin <mdounin на mdounin.ru>
> # Date 1547495341 -10800
> #      Mon Jan 14 22:49:01 2019 +0300
> # Node ID 271bd1fa164251de128cdc35dc1295ceaaa06a30
> # Parent  6d15e452fa2eaf19408e24a0d0fcc3a31344a289
> Mail: proxy_bind.
>
> diff --git a/src/mail/ngx_mail_proxy_module.c
> b/src/mail/ngx_mail_proxy_module.c
> --- a/src/mail/ngx_mail_proxy_module.c
> +++ b/src/mail/ngx_mail_proxy_module.c
> @@ -13,11 +13,12 @@
>
>
>  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_flag_t   enable;
> +    ngx_flag_t   pass_error_message;
> +    ngx_flag_t   xclient;
> +    size_t       buffer_size;
> +    ngx_msec_t   timeout;
> +    ngx_addr_t  *local;
>  } ngx_mail_proxy_conf_t;
>
>
> @@ -35,6 +36,8 @@ static void ngx_mail_proxy_close_session
>  static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
>  static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
>      void *child);
> +static char *ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,
> +    void *conf);
>
>
>  static ngx_command_t  ngx_mail_proxy_commands[] = {
> @@ -60,6 +63,13 @@ static ngx_command_t  ngx_mail_proxy_com
>        offsetof(ngx_mail_proxy_conf_t, timeout),
>        NULL },
>
> +    { ngx_string("proxy_bind"),
> +      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
> +      ngx_mail_proxy_bind,
> +      NGX_MAIL_SRV_CONF_OFFSET,
> +      0,
> +      NULL },
> +
>      { ngx_string("proxy_pass_error_message"),
>        NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
>        ngx_conf_set_flag_slot,
> @@ -118,6 +128,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *
>
>      s->connection->log->action = "connecting to upstream";
>
> +    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
>      cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
>
>      p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t));
> @@ -134,6 +145,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *
>      p->upstream.get = ngx_event_get_peer;
>      p->upstream.log = s->connection->log;
>      p->upstream.log_error = NGX_ERROR_ERR;
> +    p->upstream.local = pcf->local;
>
>      rc = ngx_event_connect_peer(&p->upstream);
>
> @@ -150,8 +162,6 @@ ngx_mail_proxy_init(ngx_mail_session_t *
>      s->connection->read->handler = ngx_mail_proxy_block_read;
>      p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;
>
> -    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
> -
>      s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
>                                             pcf->buffer_size);
>      if (s->proxy->buffer == NULL) {
> @@ -1104,6 +1114,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c
>      pcf->xclient = NGX_CONF_UNSET;
>      pcf->buffer_size = NGX_CONF_UNSET_SIZE;
>      pcf->timeout = NGX_CONF_UNSET_MSEC;
> +    pcf->local = NGX_CONF_UNSET_PTR;
>
>      return pcf;
>  }
> @@ -1121,6 +1132,52 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf
>      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);
> +    ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
>
>      return NGX_CONF_OK;
>  }
> +
> +
> +static char *
> +ngx_mail_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
> +{
> +    ngx_mail_proxy_conf_t  *pcf = conf;
> +
> +    ngx_int_t   rc;
> +    ngx_str_t  *value;
> +
> +    if (pcf->local != NGX_CONF_UNSET_PTR) {
> +        return "is duplicate";
> +    }
> +
> +    value = cf->args->elts;
> +
> +    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) {
> +        pcf->local = NULL;
> +        return NGX_CONF_OK;
> +    }
> +
> +    pcf->local = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
> +    if (pcf->local == NULL) {
> +        return NGX_CONF_ERROR;
> +    }
> +
> +    rc = ngx_parse_addr_port(cf->pool, pcf->local, value[1].data,
> +                             value[1].len);
> +
> +    switch (rc) {
> +    case NGX_OK:
> +        pcf->local->name = value[1];
> +        break;
> +
> +    case NGX_DECLINED:
> +        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> +                           "invalid address \"%V\"", &value[1]);
> +        /* fall through */
> +
> +    default:
> +        return NGX_CONF_ERROR;
> +    }
> +
> +    return NGX_CONF_OK;
> +}
>
>
> --
> Maxim Dounin
> http://mdounin.ru/
> _______________________________________________
> nginx-ru mailing list
> nginx-ru на nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-ru
----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mailman.nginx.org/pipermail/nginx-ru/attachments/20190115/ab1fe3a5/attachment-0001.html>


Подробная информация о списке рассылки nginx-ru