# HG changeset patch # User Igor Sysoev # Date 1202910604 0 # Node ID 057d362ee50e48980e32c4864ff08f8c213f73fa # Parent 782af103811564ef34698ec919b2469e15566d70 resolver in smtp proxy module diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -81,6 +81,7 @@ typedef struct { ngx_mail_protocol_t *protocol; ngx_msec_t timeout; + ngx_msec_t resolver_timeout; ngx_flag_t so_keepalive; @@ -89,6 +90,8 @@ typedef struct { u_char *file_name; ngx_int_t line; + ngx_resolver_t *resolver; + /* server ctx */ ngx_mail_conf_ctx_t *ctx; } ngx_mail_core_srv_conf_t; @@ -147,6 +150,8 @@ typedef struct { void **main_conf; void **srv_conf; + ngx_resolver_ctx_t *resolver_ctx; + ngx_mail_proxy_ctx_t *proxy; ngx_uint_t mail_state; @@ -171,6 +176,7 @@ typedef struct { ngx_str_t text; ngx_str_t *addr_text; + ngx_str_t host; ngx_str_t smtp_helo; ngx_uint_t command; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -20,6 +20,8 @@ static char *ngx_mail_core_listen(ngx_co void *conf); static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_mail_core_commands[] = { @@ -66,6 +68,20 @@ static ngx_command_t ngx_mail_core_comm offsetof(ngx_mail_core_srv_conf_t, server_name), NULL }, + { ngx_string("resolver"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_core_resolver, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_timeout"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), + NULL }, + ngx_null_command }; @@ -138,11 +154,16 @@ ngx_mail_core_create_srv_conf(ngx_conf_t * set by ngx_pcalloc(): * * cscf->protocol = NULL; + * cscf->resolver = NULL; */ cscf->timeout = NGX_CONF_UNSET_MSEC; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->so_keepalive = NGX_CONF_UNSET; + cscf->file_name = cf->conf_file->file.name.data; + cscf->line = cf->conf_file->line; + return cscf; } @@ -154,6 +175,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t ngx_mail_core_srv_conf_t *conf = child; ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, + 30000); ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); @@ -184,6 +207,10 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t return NGX_CONF_ERROR; } + if (conf->resolver == NULL) { + conf->resolver = prev->resolver; + } + return NGX_CONF_OK; } @@ -237,9 +264,6 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index]; cscf->ctx = ctx; - cscf->file_name = cf->conf_file->file.name.data; - cscf->line = cf->conf_file->line; - cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cscfp = ngx_array_push(&cmcf->servers); @@ -389,6 +413,35 @@ ngx_mail_core_protocol(ngx_conf_t *cf, n } +static char * +ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_core_srv_conf_t *cscf = conf; + + ngx_url_t u; + ngx_str_t *value; + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = value[1]; + u.port = 53; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); + return NGX_CONF_ERROR; + } + + cscf->resolver = ngx_resolver_create(&u.addrs[0], cf->cycle->new_log); + if (cscf->resolver == NULL) { + return NGX_OK; + } + + return NGX_CONF_OK; +} + + char * ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 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 @@ -528,10 +528,10 @@ ngx_mail_proxy_smtp_handler(ngx_event_t s->connection->log->action = "sending XCLIENT to upstream"; - line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= " - "NAME=[UNAVAILABLE]" CRLF) - 1 + line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME=" + CRLF) - 1 + s->esmtp + s->smtp_helo.len - + s->connection->addr_text.len + s->login.len; + + s->connection->addr_text.len + s->login.len + s->host.len; line.data = ngx_palloc(c->pool, line.len); if (line.data == NULL) { @@ -542,15 +542,14 @@ ngx_mail_proxy_smtp_handler(ngx_event_t if (s->smtp_helo.len) { line.len = ngx_sprintf(line.data, "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V " - "NAME=[UNAVAILABLE]" CRLF, + "NAME=%V" CRLF, (s->esmtp ? "E" : ""), &s->smtp_helo, - &s->connection->addr_text, &s->login) + &s->connection->addr_text, &s->login, &s->host) - 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) + "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V NAME=%V" CRLF, + &s->connection->addr_text, &s->login, &s->host) - line.data; } diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -11,6 +11,9 @@ #include +static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c); @@ -40,13 +43,176 @@ static u_char smtp_invalid_argument[] = static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; +static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]"); +static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); + + void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) { + struct sockaddr_in *sin; + ngx_resolver_ctx_t *ctx; + ngx_mail_core_srv_conf_t *cscf; + + c->log->action = "in resolving client address"; + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + ctx->addr = sin->sin_addr.s_addr; + ctx->handler = ngx_mail_smtp_resolve_addr_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_addr(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &c->addr_text, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + ngx_resolve_addr_done(ctx); + + ngx_mail_smtp_greeting(s, s->connection); + + return; + } + + c->log->action = "in resolving client hostname"; + + s->host.data = ngx_pstrdup(c->pool, &ctx->name); + if (s->host.data == NULL) { + ngx_resolve_addr_done(ctx); + ngx_mail_close_connection(c); + return; + } + + s->host.len = ctx->name.len; + + ngx_resolve_addr_done(ctx); + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "address resolved: %V", &s->host); + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + ctx->name = s->host; + ctx->type = NGX_RESOLVE_A; + ctx->handler = ngx_mail_smtp_resolve_name_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_name(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) +{ + in_addr_t addr; + ngx_uint_t i; + ngx_connection_t *c; + struct sockaddr_in *sin; + ngx_mail_session_t *s; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + } else { + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + for (i = 0; i < ctx->naddrs; i++) { + + addr = ctx->addrs[i]; + + ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, + "name was resolved to %ud.%ud.%ud.%ud", + (ntohl(addr) >> 24) & 0xff, + (ntohl(addr) >> 16) & 0xff, + (ntohl(addr) >> 8) & 0xff, + ntohl(addr) & 0xff); + + if (addr == sin->sin_addr.s_addr) { + goto found; + } + } + + s->host = smtp_unavailable; + } + +found: + + ngx_resolve_name_done(ctx); + + ngx_mail_smtp_greeting(s, c); +} + + +static void +ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) +{ ngx_msec_t timeout; ngx_mail_core_srv_conf_t *cscf; ngx_mail_smtp_srv_conf_t *sscf; + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "smtp greeting for \"%V\"", &s->host); + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -158,6 +158,15 @@ ngx_mail_smtp_merge_srv_conf(ngx_conf_t cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module); + if (cscf->protocol->type == NGX_MAIL_SMTP_PROTOCOL + && cscf->resolver == NULL) + { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "undefined resolver for server in %s:%ui", + cscf->file_name, cscf->line); + return NGX_CONF_ERROR; + } + size = sizeof("220 ESMTP ready" CRLF) - 1 + cscf->server_name.len; p = ngx_palloc(cf->pool, size);