Спасибо за развернутый ответ и патч. Мы модифицировали патч, добавив логику перебора 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 <mdou...@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 <mdou...@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
_______________________________________________ nginx-ru mailing list nginx-ru@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-ru