resolver in smtp proxy module
Igor Sysoev
14 years ago
80 | 80 | ngx_mail_protocol_t *protocol; |
81 | 81 | |
82 | 82 | ngx_msec_t timeout; |
83 | ngx_msec_t resolver_timeout; | |
83 | 84 | |
84 | 85 | ngx_flag_t so_keepalive; |
85 | 86 | |
87 | 88 | |
88 | 89 | u_char *file_name; |
89 | 90 | ngx_int_t line; |
91 | ||
92 | ngx_resolver_t *resolver; | |
90 | 93 | |
91 | 94 | /* server ctx */ |
92 | 95 | ngx_mail_conf_ctx_t *ctx; |
146 | 149 | void **main_conf; |
147 | 150 | void **srv_conf; |
148 | 151 | |
152 | ngx_resolver_ctx_t *resolver_ctx; | |
153 | ||
149 | 154 | ngx_mail_proxy_ctx_t *proxy; |
150 | 155 | |
151 | 156 | ngx_uint_t mail_state; |
170 | 175 | ngx_str_t text; |
171 | 176 | |
172 | 177 | ngx_str_t *addr_text; |
178 | ngx_str_t host; | |
173 | 179 | ngx_str_t smtp_helo; |
174 | 180 | |
175 | 181 | ngx_uint_t command; |
19 | 19 | void *conf); |
20 | 20 | static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, |
21 | 21 | void *conf); |
22 | static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, | |
23 | void *conf); | |
22 | 24 | |
23 | 25 | |
24 | 26 | static ngx_command_t ngx_mail_core_commands[] = { |
63 | 65 | ngx_conf_set_str_slot, |
64 | 66 | NGX_MAIL_SRV_CONF_OFFSET, |
65 | 67 | offsetof(ngx_mail_core_srv_conf_t, server_name), |
68 | NULL }, | |
69 | ||
70 | { ngx_string("resolver"), | |
71 | NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
72 | ngx_mail_core_resolver, | |
73 | NGX_MAIL_SRV_CONF_OFFSET, | |
74 | 0, | |
75 | NULL }, | |
76 | ||
77 | { ngx_string("resolver_timeout"), | |
78 | NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
79 | ngx_conf_set_msec_slot, | |
80 | NGX_MAIL_SRV_CONF_OFFSET, | |
81 | offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), | |
66 | 82 | NULL }, |
67 | 83 | |
68 | 84 | ngx_null_command |
137 | 153 | * set by ngx_pcalloc(): |
138 | 154 | * |
139 | 155 | * cscf->protocol = NULL; |
156 | * cscf->resolver = NULL; | |
140 | 157 | */ |
141 | 158 | |
142 | 159 | cscf->timeout = NGX_CONF_UNSET_MSEC; |
160 | cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; | |
143 | 161 | cscf->so_keepalive = NGX_CONF_UNSET; |
162 | ||
163 | cscf->file_name = cf->conf_file->file.name.data; | |
164 | cscf->line = cf->conf_file->line; | |
144 | 165 | |
145 | 166 | return cscf; |
146 | 167 | } |
153 | 174 | ngx_mail_core_srv_conf_t *conf = child; |
154 | 175 | |
155 | 176 | ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); |
177 | ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, | |
178 | 30000); | |
156 | 179 | |
157 | 180 | ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); |
158 | 181 | |
181 | 204 | "unknown mail protocol for server in %s:%ui", |
182 | 205 | conf->file_name, conf->line); |
183 | 206 | return NGX_CONF_ERROR; |
207 | } | |
208 | ||
209 | if (conf->resolver == NULL) { | |
210 | conf->resolver = prev->resolver; | |
184 | 211 | } |
185 | 212 | |
186 | 213 | return NGX_CONF_OK; |
236 | 263 | cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index]; |
237 | 264 | cscf->ctx = ctx; |
238 | 265 | |
239 | cscf->file_name = cf->conf_file->file.name.data; | |
240 | cscf->line = cf->conf_file->line; | |
241 | ||
242 | 266 | cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; |
243 | 267 | |
244 | 268 | cscfp = ngx_array_push(&cmcf->servers); |
388 | 412 | } |
389 | 413 | |
390 | 414 | |
415 | static char * | |
416 | ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
417 | { | |
418 | ngx_mail_core_srv_conf_t *cscf = conf; | |
419 | ||
420 | ngx_url_t u; | |
421 | ngx_str_t *value; | |
422 | ||
423 | value = cf->args->elts; | |
424 | ||
425 | ngx_memzero(&u, sizeof(ngx_url_t)); | |
426 | ||
427 | u.host = value[1]; | |
428 | u.port = 53; | |
429 | ||
430 | if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { | |
431 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); | |
432 | return NGX_CONF_ERROR; | |
433 | } | |
434 | ||
435 | cscf->resolver = ngx_resolver_create(&u.addrs[0], cf->cycle->new_log); | |
436 | if (cscf->resolver == NULL) { | |
437 | return NGX_OK; | |
438 | } | |
439 | ||
440 | return NGX_CONF_OK; | |
441 | } | |
442 | ||
443 | ||
391 | 444 | char * |
392 | 445 | ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
393 | 446 | { |
527 | 527 | |
528 | 528 | s->connection->log->action = "sending XCLIENT to upstream"; |
529 | 529 | |
530 | line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= " | |
531 | "NAME=[UNAVAILABLE]" CRLF) - 1 | |
530 | line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME=" | |
531 | CRLF) - 1 | |
532 | 532 | + s->esmtp + s->smtp_helo.len |
533 | + s->connection->addr_text.len + s->login.len; | |
533 | + s->connection->addr_text.len + s->login.len + s->host.len; | |
534 | 534 | |
535 | 535 | line.data = ngx_palloc(c->pool, line.len); |
536 | 536 | if (line.data == NULL) { |
541 | 541 | if (s->smtp_helo.len) { |
542 | 542 | line.len = ngx_sprintf(line.data, |
543 | 543 | "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V " |
544 | "NAME=[UNAVAILABLE]" CRLF, | |
544 | "NAME=%V" CRLF, | |
545 | 545 | (s->esmtp ? "E" : ""), &s->smtp_helo, |
546 | &s->connection->addr_text, &s->login) | |
546 | &s->connection->addr_text, &s->login, &s->host) | |
547 | 547 | - line.data; |
548 | 548 | } else { |
549 | 549 | line.len = ngx_sprintf(line.data, |
550 | "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V " | |
551 | "NAME=[UNAVAILABLE]" CRLF, | |
552 | &s->connection->addr_text, &s->login) | |
550 | "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V NAME=%V" CRLF, | |
551 | &s->connection->addr_text, &s->login, &s->host) | |
553 | 552 | - line.data; |
554 | 553 | } |
555 | 554 |
10 | 10 | #include <ngx_mail_smtp_module.h> |
11 | 11 | |
12 | 12 | |
13 | static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); | |
14 | static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); | |
15 | static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); | |
13 | 16 | static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); |
14 | 17 | static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, |
15 | 18 | ngx_connection_t *c); |
39 | 42 | static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; |
40 | 43 | |
41 | 44 | |
45 | static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]"); | |
46 | static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); | |
47 | ||
48 | ||
42 | 49 | void |
43 | 50 | ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) |
51 | { | |
52 | struct sockaddr_in *sin; | |
53 | ngx_resolver_ctx_t *ctx; | |
54 | ngx_mail_core_srv_conf_t *cscf; | |
55 | ||
56 | c->log->action = "in resolving client address"; | |
57 | ||
58 | cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
59 | ||
60 | ctx = ngx_resolve_start(cscf->resolver, NULL); | |
61 | if (ctx == NULL) { | |
62 | ngx_mail_close_connection(c); | |
63 | return; | |
64 | } | |
65 | ||
66 | /* AF_INET only */ | |
67 | ||
68 | sin = (struct sockaddr_in *) c->sockaddr; | |
69 | ||
70 | ctx->addr = sin->sin_addr.s_addr; | |
71 | ctx->handler = ngx_mail_smtp_resolve_addr_handler; | |
72 | ctx->data = s; | |
73 | ctx->timeout = cscf->resolver_timeout; | |
74 | ||
75 | if (ngx_resolve_addr(ctx) != NGX_OK) { | |
76 | ngx_mail_close_connection(c); | |
77 | } | |
78 | } | |
79 | ||
80 | ||
81 | static void | |
82 | ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx) | |
83 | { | |
84 | ngx_connection_t *c; | |
85 | ngx_mail_session_t *s; | |
86 | ngx_mail_core_srv_conf_t *cscf; | |
87 | ||
88 | s = ctx->data; | |
89 | c = s->connection; | |
90 | ||
91 | if (ctx->state) { | |
92 | ngx_log_error(NGX_LOG_ERR, c->log, 0, | |
93 | "%V could not be resolved (%i: %s)", | |
94 | &c->addr_text, ctx->state, | |
95 | ngx_resolver_strerror(ctx->state)); | |
96 | ||
97 | if (ctx->state == NGX_RESOLVE_NXDOMAIN) { | |
98 | s->host = smtp_unavailable; | |
99 | ||
100 | } else { | |
101 | s->host = smtp_tempunavail; | |
102 | } | |
103 | ||
104 | ngx_resolve_addr_done(ctx); | |
105 | ||
106 | ngx_mail_smtp_greeting(s, s->connection); | |
107 | ||
108 | return; | |
109 | } | |
110 | ||
111 | c->log->action = "in resolving client hostname"; | |
112 | ||
113 | s->host.data = ngx_pstrdup(c->pool, &ctx->name); | |
114 | if (s->host.data == NULL) { | |
115 | ngx_resolve_addr_done(ctx); | |
116 | ngx_mail_close_connection(c); | |
117 | return; | |
118 | } | |
119 | ||
120 | s->host.len = ctx->name.len; | |
121 | ||
122 | ngx_resolve_addr_done(ctx); | |
123 | ||
124 | ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
125 | "address resolved: %V", &s->host); | |
126 | ||
127 | cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
128 | ||
129 | ctx = ngx_resolve_start(cscf->resolver, NULL); | |
130 | if (ctx == NULL) { | |
131 | ngx_mail_close_connection(c); | |
132 | return; | |
133 | } | |
134 | ||
135 | ctx->name = s->host; | |
136 | ctx->type = NGX_RESOLVE_A; | |
137 | ctx->handler = ngx_mail_smtp_resolve_name_handler; | |
138 | ctx->data = s; | |
139 | ctx->timeout = cscf->resolver_timeout; | |
140 | ||
141 | if (ngx_resolve_name(ctx) != NGX_OK) { | |
142 | ngx_mail_close_connection(c); | |
143 | } | |
144 | } | |
145 | ||
146 | ||
147 | static void | |
148 | ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) | |
149 | { | |
150 | in_addr_t addr; | |
151 | ngx_uint_t i; | |
152 | ngx_connection_t *c; | |
153 | struct sockaddr_in *sin; | |
154 | ngx_mail_session_t *s; | |
155 | ||
156 | s = ctx->data; | |
157 | c = s->connection; | |
158 | ||
159 | if (ctx->state) { | |
160 | ngx_log_error(NGX_LOG_ERR, c->log, 0, | |
161 | "%V could not be resolved (%i: %s)", | |
162 | &ctx->name, ctx->state, | |
163 | ngx_resolver_strerror(ctx->state)); | |
164 | ||
165 | if (ctx->state == NGX_RESOLVE_NXDOMAIN) { | |
166 | s->host = smtp_unavailable; | |
167 | ||
168 | } else { | |
169 | s->host = smtp_tempunavail; | |
170 | } | |
171 | ||
172 | } else { | |
173 | ||
174 | /* AF_INET only */ | |
175 | ||
176 | sin = (struct sockaddr_in *) c->sockaddr; | |
177 | ||
178 | for (i = 0; i < ctx->naddrs; i++) { | |
179 | ||
180 | addr = ctx->addrs[i]; | |
181 | ||
182 | ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
183 | "name was resolved to %ud.%ud.%ud.%ud", | |
184 | (ntohl(addr) >> 24) & 0xff, | |
185 | (ntohl(addr) >> 16) & 0xff, | |
186 | (ntohl(addr) >> 8) & 0xff, | |
187 | ntohl(addr) & 0xff); | |
188 | ||
189 | if (addr == sin->sin_addr.s_addr) { | |
190 | goto found; | |
191 | } | |
192 | } | |
193 | ||
194 | s->host = smtp_unavailable; | |
195 | } | |
196 | ||
197 | found: | |
198 | ||
199 | ngx_resolve_name_done(ctx); | |
200 | ||
201 | ngx_mail_smtp_greeting(s, c); | |
202 | } | |
203 | ||
204 | ||
205 | static void | |
206 | ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) | |
44 | 207 | { |
45 | 208 | ngx_msec_t timeout; |
46 | 209 | ngx_mail_core_srv_conf_t *cscf; |
47 | 210 | ngx_mail_smtp_srv_conf_t *sscf; |
211 | ||
212 | ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, | |
213 | "smtp greeting for \"%V\"", &s->host); | |
48 | 214 | |
49 | 215 | cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); |
50 | 216 | sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); |
157 | 157 | |
158 | 158 | cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module); |
159 | 159 | |
160 | if (cscf->protocol->type == NGX_MAIL_SMTP_PROTOCOL | |
161 | && cscf->resolver == NULL) | |
162 | { | |
163 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
164 | "undefined resolver for server in %s:%ui", | |
165 | cscf->file_name, cscf->line); | |
166 | return NGX_CONF_ERROR; | |
167 | } | |
168 | ||
160 | 169 | size = sizeof("220 ESMTP ready" CRLF) - 1 + cscf->server_name.len; |
161 | 170 | |
162 | 171 | p = ngx_palloc(cf->pool, size); |