Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_proxy_module.c @ 436:9b19e26b2660
Mail: smtp pipelining support.
Basically, this does the following two changes (and corresponding
modifications of related code):
1. Does not reset session buffer unless it's reached it's end, and always
wait for LF to terminate command (even if we detected invalid command).
2. Record command name as the first argument to make it available for
handlers (since now we can't assume that command starts from s->buffer->start).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 11 Sep 2008 15:26:25 +0400 |
parents | 375518f786db |
children | d67e93e97b4a |
rev | line source |
---|---|
290 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_event_connect.h> | |
11 #include <ngx_mail.h> | |
12 | |
13 | |
14 typedef struct { | |
15 ngx_flag_t enable; | |
16 ngx_flag_t pass_error_message; | |
17 ngx_flag_t xclient; | |
18 size_t buffer_size; | |
19 ngx_msec_t timeout; | |
20 } ngx_mail_proxy_conf_t; | |
21 | |
22 | |
23 static void ngx_mail_proxy_block_read(ngx_event_t *rev); | |
24 static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev); | |
25 static void ngx_mail_proxy_imap_handler(ngx_event_t *rev); | |
26 static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev); | |
27 static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev); | |
28 static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s, | |
29 ngx_uint_t state); | |
30 static void ngx_mail_proxy_handler(ngx_event_t *ev); | |
31 static void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s); | |
32 static void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s); | |
33 static void ngx_mail_proxy_close_session(ngx_mail_session_t *s); | |
34 static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf); | |
35 static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, | |
36 void *child); | |
37 | |
38 | |
39 static ngx_command_t ngx_mail_proxy_commands[] = { | |
40 | |
41 { ngx_string("proxy"), | |
42 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, | |
43 ngx_conf_set_flag_slot, | |
44 NGX_MAIL_SRV_CONF_OFFSET, | |
45 offsetof(ngx_mail_proxy_conf_t, enable), | |
46 NULL }, | |
47 | |
48 { ngx_string("proxy_buffer"), | |
49 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
50 ngx_conf_set_size_slot, | |
51 NGX_MAIL_SRV_CONF_OFFSET, | |
52 offsetof(ngx_mail_proxy_conf_t, buffer_size), | |
53 NULL }, | |
54 | |
55 { ngx_string("proxy_timeout"), | |
56 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
57 ngx_conf_set_msec_slot, | |
58 NGX_MAIL_SRV_CONF_OFFSET, | |
59 offsetof(ngx_mail_proxy_conf_t, timeout), | |
60 NULL }, | |
61 | |
62 { ngx_string("proxy_pass_error_message"), | |
63 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
64 ngx_conf_set_flag_slot, | |
65 NGX_MAIL_SRV_CONF_OFFSET, | |
66 offsetof(ngx_mail_proxy_conf_t, pass_error_message), | |
67 NULL }, | |
68 | |
69 { ngx_string("xclient"), | |
70 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, | |
71 ngx_conf_set_flag_slot, | |
72 NGX_MAIL_SRV_CONF_OFFSET, | |
73 offsetof(ngx_mail_proxy_conf_t, xclient), | |
74 NULL }, | |
75 | |
76 ngx_null_command | |
77 }; | |
78 | |
79 | |
80 static ngx_mail_module_t ngx_mail_proxy_module_ctx = { | |
336 | 81 NULL, /* protocol */ |
82 | |
290 | 83 NULL, /* create main configuration */ |
84 NULL, /* init main configuration */ | |
85 | |
86 ngx_mail_proxy_create_conf, /* create server configuration */ | |
87 ngx_mail_proxy_merge_conf /* merge server configuration */ | |
88 }; | |
89 | |
90 | |
91 ngx_module_t ngx_mail_proxy_module = { | |
92 NGX_MODULE_V1, | |
93 &ngx_mail_proxy_module_ctx, /* module context */ | |
94 ngx_mail_proxy_commands, /* module directives */ | |
95 NGX_MAIL_MODULE, /* module type */ | |
96 NULL, /* init master */ | |
97 NULL, /* init module */ | |
98 NULL, /* init process */ | |
99 NULL, /* init thread */ | |
100 NULL, /* exit thread */ | |
101 NULL, /* exit process */ | |
102 NULL, /* exit master */ | |
103 NGX_MODULE_V1_PADDING | |
104 }; | |
105 | |
106 | |
434
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
107 static u_char smtp_ok[] = "235 2.0.0 OK" CRLF; |
290 | 108 |
109 | |
110 void | |
111 ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer) | |
112 { | |
113 int keepalive; | |
114 ngx_int_t rc; | |
115 ngx_mail_proxy_ctx_t *p; | |
116 ngx_mail_proxy_conf_t *pcf; | |
117 ngx_mail_core_srv_conf_t *cscf; | |
118 | |
119 s->connection->log->action = "connecting to upstream"; | |
120 | |
121 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
122 | |
123 if (cscf->so_keepalive) { | |
124 keepalive = 1; | |
125 | |
126 if (setsockopt(s->connection->fd, SOL_SOCKET, SO_KEEPALIVE, | |
127 (const void *) &keepalive, sizeof(int)) | |
128 == -1) | |
129 { | |
130 ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, | |
131 "setsockopt(SO_KEEPALIVE) failed"); | |
132 } | |
133 } | |
134 | |
135 p = ngx_pcalloc(s->connection->pool, sizeof(ngx_mail_proxy_ctx_t)); | |
136 if (p == NULL) { | |
137 ngx_mail_session_internal_server_error(s); | |
138 return; | |
139 } | |
140 | |
141 s->proxy = p; | |
142 | |
143 p->upstream.sockaddr = peer->sockaddr; | |
144 p->upstream.socklen = peer->socklen; | |
145 p->upstream.name = &peer->name; | |
146 p->upstream.get = ngx_event_get_peer; | |
147 p->upstream.log = s->connection->log; | |
148 p->upstream.log_error = NGX_ERROR_ERR; | |
149 | |
150 rc = ngx_event_connect_peer(&p->upstream); | |
151 | |
152 if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { | |
153 ngx_mail_proxy_internal_server_error(s); | |
154 return; | |
155 } | |
156 | |
157 ngx_add_timer(p->upstream.connection->read, cscf->timeout); | |
158 | |
159 p->upstream.connection->data = s; | |
160 p->upstream.connection->pool = s->connection->pool; | |
161 | |
162 s->connection->read->handler = ngx_mail_proxy_block_read; | |
163 p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler; | |
164 | |
165 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
166 | |
167 s->proxy->buffer = ngx_create_temp_buf(s->connection->pool, | |
168 pcf->buffer_size); | |
169 if (s->proxy->buffer == NULL) { | |
170 ngx_mail_proxy_internal_server_error(s); | |
171 return; | |
172 } | |
173 | |
372 | 174 s->out.len = 0; |
175 | |
290 | 176 switch (s->protocol) { |
177 | |
178 case NGX_MAIL_POP3_PROTOCOL: | |
179 p->upstream.connection->read->handler = ngx_mail_proxy_pop3_handler; | |
180 s->mail_state = ngx_pop3_start; | |
181 break; | |
182 | |
183 case NGX_MAIL_IMAP_PROTOCOL: | |
184 p->upstream.connection->read->handler = ngx_mail_proxy_imap_handler; | |
185 s->mail_state = ngx_imap_start; | |
186 break; | |
187 | |
188 default: /* NGX_MAIL_SMTP_PROTOCOL */ | |
189 p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler; | |
190 s->mail_state = ngx_smtp_start; | |
191 break; | |
192 } | |
193 } | |
194 | |
195 | |
196 static void | |
197 ngx_mail_proxy_block_read(ngx_event_t *rev) | |
198 { | |
199 ngx_connection_t *c; | |
200 ngx_mail_session_t *s; | |
201 | |
202 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy block read"); | |
203 | |
204 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { | |
205 c = rev->data; | |
206 s = c->data; | |
207 | |
208 ngx_mail_proxy_close_session(s); | |
209 } | |
210 } | |
211 | |
212 | |
213 static void | |
214 ngx_mail_proxy_pop3_handler(ngx_event_t *rev) | |
215 { | |
216 u_char *p; | |
217 ngx_int_t rc; | |
218 ngx_str_t line; | |
219 ngx_connection_t *c; | |
220 ngx_mail_session_t *s; | |
221 ngx_mail_proxy_conf_t *pcf; | |
222 | |
223 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, | |
224 "mail proxy pop3 auth handler"); | |
225 | |
226 c = rev->data; | |
227 s = c->data; | |
228 | |
229 if (rev->timedout) { | |
230 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, | |
231 "upstream timed out"); | |
232 c->timedout = 1; | |
233 ngx_mail_proxy_internal_server_error(s); | |
234 return; | |
235 } | |
236 | |
237 rc = ngx_mail_proxy_read_response(s, 0); | |
238 | |
239 if (rc == NGX_AGAIN) { | |
240 return; | |
241 } | |
242 | |
243 if (rc == NGX_ERROR) { | |
244 ngx_mail_proxy_upstream_error(s); | |
245 return; | |
246 } | |
247 | |
248 switch (s->mail_state) { | |
249 | |
250 case ngx_pop3_start: | |
251 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user"); | |
252 | |
253 s->connection->log->action = "sending user name to upstream"; | |
254 | |
255 line.len = sizeof("USER ") - 1 + s->login.len + 2; | |
382 | 256 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 257 if (line.data == NULL) { |
258 ngx_mail_proxy_internal_server_error(s); | |
259 return; | |
260 } | |
261 | |
262 p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1); | |
263 p = ngx_cpymem(p, s->login.data, s->login.len); | |
264 *p++ = CR; *p = LF; | |
265 | |
266 s->mail_state = ngx_pop3_user; | |
267 break; | |
268 | |
269 case ngx_pop3_user: | |
270 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send pass"); | |
271 | |
272 s->connection->log->action = "sending password to upstream"; | |
273 | |
274 line.len = sizeof("PASS ") - 1 + s->passwd.len + 2; | |
382 | 275 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 276 if (line.data == NULL) { |
277 ngx_mail_proxy_internal_server_error(s); | |
278 return; | |
279 } | |
280 | |
281 p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1); | |
282 p = ngx_cpymem(p, s->passwd.data, s->passwd.len); | |
283 *p++ = CR; *p = LF; | |
284 | |
285 s->mail_state = ngx_pop3_passwd; | |
286 break; | |
287 | |
288 case ngx_pop3_passwd: | |
289 s->connection->read->handler = ngx_mail_proxy_handler; | |
290 s->connection->write->handler = ngx_mail_proxy_handler; | |
291 rev->handler = ngx_mail_proxy_handler; | |
292 c->write->handler = ngx_mail_proxy_handler; | |
293 | |
294 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
295 ngx_add_timer(s->connection->read, pcf->timeout); | |
296 ngx_del_timer(c->read); | |
297 | |
298 c->log->action = NULL; | |
299 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); | |
300 | |
301 ngx_mail_proxy_handler(s->connection->write); | |
302 | |
303 return; | |
304 | |
305 default: | |
306 #if (NGX_SUPPRESS_WARN) | |
307 line.len = 0; | |
308 line.data = NULL; | |
309 #endif | |
310 break; | |
311 } | |
312 | |
313 if (c->send(c, line.data, line.len) < (ssize_t) line.len) { | |
314 /* | |
315 * we treat the incomplete sending as NGX_ERROR | |
316 * because it is very strange here | |
317 */ | |
318 ngx_mail_proxy_internal_server_error(s); | |
319 return; | |
320 } | |
321 | |
322 s->proxy->buffer->pos = s->proxy->buffer->start; | |
323 s->proxy->buffer->last = s->proxy->buffer->start; | |
324 } | |
325 | |
326 | |
327 static void | |
328 ngx_mail_proxy_imap_handler(ngx_event_t *rev) | |
329 { | |
330 u_char *p; | |
331 ngx_int_t rc; | |
332 ngx_str_t line; | |
333 ngx_connection_t *c; | |
334 ngx_mail_session_t *s; | |
335 ngx_mail_proxy_conf_t *pcf; | |
336 | |
337 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, | |
338 "mail proxy imap auth handler"); | |
339 | |
340 c = rev->data; | |
341 s = c->data; | |
342 | |
343 if (rev->timedout) { | |
344 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, | |
345 "upstream timed out"); | |
346 c->timedout = 1; | |
347 ngx_mail_proxy_internal_server_error(s); | |
348 return; | |
349 } | |
350 | |
351 rc = ngx_mail_proxy_read_response(s, s->mail_state); | |
352 | |
353 if (rc == NGX_AGAIN) { | |
354 return; | |
355 } | |
356 | |
357 if (rc == NGX_ERROR) { | |
358 ngx_mail_proxy_upstream_error(s); | |
359 return; | |
360 } | |
361 | |
362 switch (s->mail_state) { | |
363 | |
364 case ngx_imap_start: | |
365 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, | |
366 "mail proxy send login"); | |
367 | |
368 s->connection->log->action = "sending LOGIN command to upstream"; | |
369 | |
370 line.len = s->tag.len + sizeof("LOGIN ") - 1 | |
371 + 1 + NGX_SIZE_T_LEN + 1 + 2; | |
382 | 372 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 373 if (line.data == NULL) { |
374 ngx_mail_proxy_internal_server_error(s); | |
375 return; | |
376 } | |
377 | |
378 line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF, | |
379 &s->tag, s->login.len) | |
380 - line.data; | |
381 | |
382 s->mail_state = ngx_imap_login; | |
383 break; | |
384 | |
385 case ngx_imap_login: | |
386 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user"); | |
387 | |
388 s->connection->log->action = "sending user name to upstream"; | |
389 | |
390 line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2; | |
382 | 391 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 392 if (line.data == NULL) { |
393 ngx_mail_proxy_internal_server_error(s); | |
394 return; | |
395 } | |
396 | |
397 line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF, | |
398 &s->login, s->passwd.len) | |
399 - line.data; | |
400 | |
401 s->mail_state = ngx_imap_user; | |
402 break; | |
403 | |
404 case ngx_imap_user: | |
405 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, | |
406 "mail proxy send passwd"); | |
407 | |
408 s->connection->log->action = "sending password to upstream"; | |
409 | |
410 line.len = s->passwd.len + 2; | |
382 | 411 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 412 if (line.data == NULL) { |
413 ngx_mail_proxy_internal_server_error(s); | |
414 return; | |
415 } | |
416 | |
417 p = ngx_cpymem(line.data, s->passwd.data, s->passwd.len); | |
418 *p++ = CR; *p = LF; | |
419 | |
420 s->mail_state = ngx_imap_passwd; | |
421 break; | |
422 | |
423 case ngx_imap_passwd: | |
424 s->connection->read->handler = ngx_mail_proxy_handler; | |
425 s->connection->write->handler = ngx_mail_proxy_handler; | |
426 rev->handler = ngx_mail_proxy_handler; | |
427 c->write->handler = ngx_mail_proxy_handler; | |
428 | |
429 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
430 ngx_add_timer(s->connection->read, pcf->timeout); | |
431 ngx_del_timer(c->read); | |
432 | |
433 c->log->action = NULL; | |
434 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); | |
435 | |
436 ngx_mail_proxy_handler(s->connection->write); | |
437 | |
438 return; | |
439 | |
440 default: | |
441 #if (NGX_SUPPRESS_WARN) | |
442 line.len = 0; | |
443 line.data = NULL; | |
444 #endif | |
445 break; | |
446 } | |
447 | |
448 if (c->send(c, line.data, line.len) < (ssize_t) line.len) { | |
449 /* | |
450 * we treat the incomplete sending as NGX_ERROR | |
451 * because it is very strange here | |
452 */ | |
453 ngx_mail_proxy_internal_server_error(s); | |
454 return; | |
455 } | |
456 | |
457 s->proxy->buffer->pos = s->proxy->buffer->start; | |
458 s->proxy->buffer->last = s->proxy->buffer->start; | |
459 } | |
460 | |
461 | |
462 static void | |
463 ngx_mail_proxy_smtp_handler(ngx_event_t *rev) | |
464 { | |
465 u_char *p; | |
466 ngx_int_t rc; | |
467 ngx_str_t line; | |
468 ngx_connection_t *c; | |
469 ngx_mail_session_t *s; | |
470 ngx_mail_proxy_conf_t *pcf; | |
471 ngx_mail_core_srv_conf_t *cscf; | |
472 | |
473 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, | |
474 "mail proxy smtp auth handler"); | |
475 | |
476 c = rev->data; | |
477 s = c->data; | |
478 | |
479 if (rev->timedout) { | |
480 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, | |
481 "upstream timed out"); | |
482 c->timedout = 1; | |
483 ngx_mail_proxy_internal_server_error(s); | |
484 return; | |
485 } | |
486 | |
487 rc = ngx_mail_proxy_read_response(s, s->mail_state); | |
488 | |
489 if (rc == NGX_AGAIN) { | |
490 return; | |
491 } | |
492 | |
493 if (rc == NGX_ERROR) { | |
494 ngx_mail_proxy_upstream_error(s); | |
495 return; | |
496 } | |
497 | |
498 switch (s->mail_state) { | |
499 | |
500 case ngx_smtp_start: | |
501 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send ehlo"); | |
502 | |
503 s->connection->log->action = "sending HELO/EHLO to upstream"; | |
504 | |
505 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); | |
506 | |
507 line.len = sizeof("HELO ") - 1 + cscf->server_name.len + 2; | |
382 | 508 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 509 if (line.data == NULL) { |
510 ngx_mail_proxy_internal_server_error(s); | |
511 return; | |
512 } | |
513 | |
514 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
515 | |
516 p = ngx_cpymem(line.data, | |
517 ((s->esmtp || pcf->xclient) ? "EHLO " : "HELO "), | |
518 sizeof("HELO ") - 1); | |
519 | |
520 p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len); | |
521 *p++ = CR; *p = LF; | |
522 | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
523 s->mail_state = pcf->xclient ? ngx_smtp_helo_xclient : |
404
481e8f936572
Mail: rename "unauth" to "none".
Maxim Dounin <mdounin@mdounin.ru>
parents:
400
diff
changeset
|
524 s->auth_method == NGX_MAIL_AUTH_NONE ? |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
525 ngx_smtp_helo_from : ngx_smtp_helo; |
290 | 526 |
527 break; | |
528 | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
529 case ngx_smtp_helo_xclient: |
290 | 530 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, |
531 "mail proxy send xclient"); | |
532 | |
533 s->connection->log->action = "sending XCLIENT to upstream"; | |
534 | |
366 | 535 line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME=" |
536 CRLF) - 1 | |
290 | 537 + s->esmtp + s->smtp_helo.len |
366 | 538 + s->connection->addr_text.len + s->login.len + s->host.len; |
290 | 539 |
382 | 540 line.data = ngx_pnalloc(c->pool, line.len); |
290 | 541 if (line.data == NULL) { |
542 ngx_mail_proxy_internal_server_error(s); | |
543 return; | |
544 } | |
545 | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
546 line.len = ngx_sprintf(line.data, |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
547 "XCLIENT PROTO=%sSMTP%s%V ADDR=%V%s%V " |
410 | 548 "NAME=%V" CRLF, |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
549 (s->esmtp ? "E" : ""), |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
550 (s->smtp_helo.len ? " HELO=" : ""), &s->smtp_helo, |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
551 &s->connection->addr_text, |
410 | 552 (s->login.len ? " LOGIN=" : ""), &s->login, &s->host) |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
553 - line.data; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
554 |
404
481e8f936572
Mail: rename "unauth" to "none".
Maxim Dounin <mdounin@mdounin.ru>
parents:
400
diff
changeset
|
555 s->mail_state = s->auth_method == NGX_MAIL_AUTH_NONE ? |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
556 ngx_smtp_xclient_from : ngx_smtp_xclient; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
557 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
558 break; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
559 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
560 case ngx_smtp_helo_from: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
561 case ngx_smtp_xclient_from: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
562 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
563 "mail proxy send mail from"); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
564 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
565 s->connection->log->action = "sending MAIL FROM to upstream"; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
566 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
567 line.len = s->smtp_from.len + sizeof(CRLF) - 1; |
410 | 568 line.data = ngx_pnalloc(c->pool, line.len); |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
569 if (line.data == NULL) { |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
570 ngx_mail_proxy_internal_server_error(s); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
571 return; |
290 | 572 } |
573 | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
574 p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
575 *p++ = CR; *p = LF; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
576 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
577 s->mail_state = ngx_smtp_from; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
578 |
290 | 579 break; |
580 | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
581 case ngx_smtp_from: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
582 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
583 "mail proxy send rcpt to"); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
584 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
585 s->connection->log->action = "sending RCPT TO to upstream"; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
586 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
587 line.len = s->smtp_to.len + sizeof(CRLF) - 1; |
410 | 588 line.data = ngx_pnalloc(c->pool, line.len); |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
589 if (line.data == NULL) { |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
590 ngx_mail_proxy_internal_server_error(s); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
591 return; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
592 } |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
593 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
594 p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len); |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
595 *p++ = CR; *p = LF; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
596 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
597 s->mail_state = ngx_smtp_to; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
598 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
599 break; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
600 |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
601 case ngx_smtp_helo: |
290 | 602 case ngx_smtp_xclient: |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
603 case ngx_smtp_to: |
290 | 604 |
434
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
605 if (s->auth_method != NGX_MAIL_AUTH_NONE) { |
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
606 ngx_memcpy(s->proxy->buffer->start, smtp_ok, |
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
607 sizeof(smtp_ok) - 1); |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
608 s->proxy->buffer->last = s->proxy->buffer->start |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
609 + sizeof(smtp_ok) - 1; |
434
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
610 s->proxy->buffer->pos = s->proxy->buffer->start; |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
611 } |
290 | 612 |
613 | |
614 s->connection->read->handler = ngx_mail_proxy_handler; | |
615 s->connection->write->handler = ngx_mail_proxy_handler; | |
616 rev->handler = ngx_mail_proxy_handler; | |
617 c->write->handler = ngx_mail_proxy_handler; | |
618 | |
619 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
620 ngx_add_timer(s->connection->read, pcf->timeout); | |
621 ngx_del_timer(c->read); | |
622 | |
623 c->log->action = NULL; | |
624 ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); | |
625 | |
436
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
626 if (s->buffer->pos == s->buffer->last) { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
627 ngx_mail_proxy_handler(s->connection->write); |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
628 |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
629 } else { |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
630 ngx_mail_proxy_handler(c->write); |
9b19e26b2660
Mail: smtp pipelining support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
434
diff
changeset
|
631 } |
290 | 632 |
633 return; | |
634 | |
635 default: | |
636 #if (NGX_SUPPRESS_WARN) | |
637 line.len = 0; | |
638 line.data = NULL; | |
639 #endif | |
640 break; | |
641 } | |
642 | |
643 if (c->send(c, line.data, line.len) < (ssize_t) line.len) { | |
644 /* | |
645 * we treat the incomplete sending as NGX_ERROR | |
646 * because it is very strange here | |
647 */ | |
648 ngx_mail_proxy_internal_server_error(s); | |
649 return; | |
650 } | |
651 | |
652 s->proxy->buffer->pos = s->proxy->buffer->start; | |
653 s->proxy->buffer->last = s->proxy->buffer->start; | |
654 } | |
655 | |
656 | |
657 static void | |
658 ngx_mail_proxy_dummy_handler(ngx_event_t *wev) | |
659 { | |
660 ngx_connection_t *c; | |
661 ngx_mail_session_t *s; | |
662 | |
663 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy dummy handler"); | |
664 | |
665 if (ngx_handle_write_event(wev, 0) == NGX_ERROR) { | |
666 c = wev->data; | |
667 s = c->data; | |
668 | |
669 ngx_mail_proxy_close_session(s); | |
670 } | |
671 } | |
672 | |
673 | |
674 static ngx_int_t | |
675 ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) | |
676 { | |
677 u_char *p; | |
678 ssize_t n; | |
679 ngx_buf_t *b; | |
680 ngx_mail_proxy_conf_t *pcf; | |
681 | |
682 s->connection->log->action = "reading response from upstream"; | |
683 | |
684 b = s->proxy->buffer; | |
685 | |
686 n = s->proxy->upstream.connection->recv(s->proxy->upstream.connection, | |
687 b->last, b->end - b->last); | |
688 | |
689 if (n == NGX_ERROR || n == 0) { | |
690 return NGX_ERROR; | |
691 } | |
692 | |
693 if (n == NGX_AGAIN) { | |
694 return NGX_AGAIN; | |
695 } | |
696 | |
697 b->last += n; | |
698 | |
699 if (b->last - b->pos < 5) { | |
700 return NGX_AGAIN; | |
701 } | |
702 | |
703 if (*(b->last - 2) != CR || *(b->last - 1) != LF) { | |
704 if (b->last == b->end) { | |
705 *(b->last - 1) = '\0'; | |
706 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
707 "upstream sent too long response line: \"%s\"", | |
708 b->pos); | |
709 return NGX_ERROR; | |
710 } | |
711 | |
712 return NGX_AGAIN; | |
713 } | |
714 | |
715 p = b->pos; | |
716 | |
717 switch (s->protocol) { | |
718 | |
719 case NGX_MAIL_POP3_PROTOCOL: | |
720 if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') { | |
721 return NGX_OK; | |
722 } | |
723 break; | |
724 | |
725 case NGX_MAIL_IMAP_PROTOCOL: | |
726 switch (state) { | |
727 | |
728 case ngx_imap_start: | |
729 if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') { | |
730 return NGX_OK; | |
731 } | |
732 break; | |
733 | |
734 case ngx_imap_login: | |
735 case ngx_imap_user: | |
736 if (p[0] == '+') { | |
737 return NGX_OK; | |
738 } | |
739 break; | |
740 | |
741 case ngx_imap_passwd: | |
742 if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) { | |
743 p += s->tag.len; | |
744 if (p[0] == 'O' && p[1] == 'K') { | |
745 return NGX_OK; | |
746 } | |
747 } | |
748 break; | |
749 } | |
750 | |
751 break; | |
752 | |
753 default: /* NGX_MAIL_SMTP_PROTOCOL */ | |
754 switch (state) { | |
755 | |
434
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
756 case ngx_smtp_to: |
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
757 return NGX_OK; |
375518f786db
Mail: don't drop connection when RCPT TO fails.
Maxim Dounin <mdounin@mdounin.ru>
parents:
410
diff
changeset
|
758 |
290 | 759 case ngx_smtp_helo: |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
760 case ngx_smtp_helo_from: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
761 case ngx_smtp_helo_xclient: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
762 case ngx_smtp_from: |
296 | 763 if (p[0] == '2' && p[1] == '5' && p[2] == '0') { |
764 return NGX_OK; | |
765 } | |
766 break; | |
290 | 767 |
768 case ngx_smtp_start: | |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
769 if (p[0] == '2' && p[1] == '2' && p[2] == '0') { |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
770 return NGX_OK; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
771 } |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
772 break; |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
773 |
290 | 774 case ngx_smtp_xclient: |
400
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
775 case ngx_smtp_xclient_from: |
f1e2fab7a46c
Mail: smtp proxy without authentication.
Maxim Dounin <mdounin@mdounin.ru>
parents:
296
diff
changeset
|
776 if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') { |
296 | 777 return NGX_OK; |
778 } | |
779 break; | |
290 | 780 } |
781 | |
296 | 782 break; |
290 | 783 } |
784 | |
785 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
786 | |
787 if (pcf->pass_error_message == 0) { | |
788 *(b->last - 2) = '\0'; | |
789 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
790 "upstream sent invalid response: \"%s\"", p); | |
791 return NGX_ERROR; | |
792 } | |
793 | |
794 s->out.len = b->last - p - 2; | |
795 s->out.data = p; | |
796 | |
797 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, | |
798 "upstream sent invalid response: \"%V\"", &s->out); | |
799 | |
800 s->out.len = b->last - b->pos; | |
801 s->out.data = b->pos; | |
802 | |
803 return NGX_ERROR; | |
804 } | |
805 | |
806 | |
807 static void | |
808 ngx_mail_proxy_handler(ngx_event_t *ev) | |
809 { | |
810 char *action, *recv_action, *send_action; | |
811 size_t size; | |
812 ssize_t n; | |
813 ngx_buf_t *b; | |
814 ngx_uint_t do_write; | |
815 ngx_connection_t *c, *src, *dst; | |
816 ngx_mail_session_t *s; | |
817 ngx_mail_proxy_conf_t *pcf; | |
818 | |
819 c = ev->data; | |
820 s = c->data; | |
821 | |
822 if (ev->timedout) { | |
823 c->log->action = "proxying"; | |
824 | |
825 if (c == s->connection) { | |
826 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, | |
827 "client timed out"); | |
828 c->timedout = 1; | |
829 | |
830 } else { | |
831 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, | |
832 "upstream timed out"); | |
833 } | |
834 | |
835 ngx_mail_proxy_close_session(s); | |
836 return; | |
837 } | |
838 | |
839 if (c == s->connection) { | |
840 if (ev->write) { | |
841 recv_action = "proxying and reading from upstream"; | |
842 send_action = "proxying and sending to client"; | |
843 src = s->proxy->upstream.connection; | |
844 dst = c; | |
845 b = s->proxy->buffer; | |
846 | |
847 } else { | |
848 recv_action = "proxying and reading from client"; | |
849 send_action = "proxying and sending to upstream"; | |
850 src = c; | |
851 dst = s->proxy->upstream.connection; | |
852 b = s->buffer; | |
853 } | |
854 | |
855 } else { | |
856 if (ev->write) { | |
857 recv_action = "proxying and reading from client"; | |
858 send_action = "proxying and sending to upstream"; | |
859 src = s->connection; | |
860 dst = c; | |
861 b = s->buffer; | |
862 | |
863 } else { | |
864 recv_action = "proxying and reading from upstream"; | |
865 send_action = "proxying and sending to client"; | |
866 src = c; | |
867 dst = s->connection; | |
868 b = s->proxy->buffer; | |
869 } | |
870 } | |
871 | |
872 do_write = ev->write ? 1 : 0; | |
873 | |
874 ngx_log_debug3(NGX_LOG_DEBUG_MAIL, ev->log, 0, | |
875 "mail proxy handler: %d, #%d > #%d", | |
876 do_write, src->fd, dst->fd); | |
877 | |
878 for ( ;; ) { | |
879 | |
880 if (do_write) { | |
881 | |
882 size = b->last - b->pos; | |
883 | |
884 if (size && dst->write->ready) { | |
885 c->log->action = send_action; | |
886 | |
887 n = dst->send(dst, b->pos, size); | |
888 | |
889 if (n == NGX_ERROR) { | |
890 ngx_mail_proxy_close_session(s); | |
891 return; | |
892 } | |
893 | |
894 if (n > 0) { | |
895 b->pos += n; | |
896 | |
897 if (b->pos == b->last) { | |
898 b->pos = b->start; | |
899 b->last = b->start; | |
900 } | |
901 } | |
902 } | |
903 } | |
904 | |
905 size = b->end - b->last; | |
906 | |
907 if (size && src->read->ready) { | |
908 c->log->action = recv_action; | |
909 | |
910 n = src->recv(src, b->last, size); | |
911 | |
912 if (n == NGX_AGAIN || n == 0) { | |
913 break; | |
914 } | |
915 | |
916 if (n > 0) { | |
917 do_write = 1; | |
918 b->last += n; | |
919 | |
920 continue; | |
921 } | |
922 | |
923 if (n == NGX_ERROR) { | |
924 src->read->eof = 1; | |
925 } | |
926 } | |
927 | |
928 break; | |
929 } | |
930 | |
931 c->log->action = "proxying"; | |
932 | |
324 | 933 if ((s->connection->read->eof && s->buffer->pos == s->buffer->last) |
934 || (s->proxy->upstream.connection->read->eof | |
935 && s->proxy->buffer->pos == s->proxy->buffer->last) | |
936 || (s->connection->read->eof | |
937 && s->proxy->upstream.connection->read->eof)) | |
290 | 938 { |
939 action = c->log->action; | |
940 c->log->action = NULL; | |
941 ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done"); | |
942 c->log->action = action; | |
943 | |
944 ngx_mail_proxy_close_session(s); | |
945 return; | |
946 } | |
947 | |
948 if (ngx_handle_write_event(dst->write, 0) == NGX_ERROR) { | |
949 ngx_mail_proxy_close_session(s); | |
950 return; | |
951 } | |
952 | |
953 if (ngx_handle_read_event(dst->read, 0) == NGX_ERROR) { | |
954 ngx_mail_proxy_close_session(s); | |
955 return; | |
956 } | |
957 | |
958 if (ngx_handle_write_event(src->write, 0) == NGX_ERROR) { | |
959 ngx_mail_proxy_close_session(s); | |
960 return; | |
961 } | |
962 | |
963 if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) { | |
964 ngx_mail_proxy_close_session(s); | |
965 return; | |
966 } | |
967 | |
968 if (c == s->connection) { | |
969 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); | |
970 ngx_add_timer(c->read, pcf->timeout); | |
971 } | |
972 } | |
973 | |
974 | |
975 static void | |
976 ngx_mail_proxy_upstream_error(ngx_mail_session_t *s) | |
977 { | |
978 if (s->proxy->upstream.connection) { | |
979 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, | |
980 "close mail proxy connection: %d", | |
981 s->proxy->upstream.connection->fd); | |
982 | |
983 ngx_close_connection(s->proxy->upstream.connection); | |
984 } | |
985 | |
986 if (s->out.len == 0) { | |
987 ngx_mail_session_internal_server_error(s); | |
988 return; | |
989 } | |
990 | |
991 s->quit = 1; | |
992 ngx_mail_send(s->connection->write); | |
993 } | |
994 | |
995 | |
996 static void | |
997 ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s) | |
998 { | |
999 if (s->proxy->upstream.connection) { | |
1000 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, | |
1001 "close mail proxy connection: %d", | |
1002 s->proxy->upstream.connection->fd); | |
1003 | |
1004 ngx_close_connection(s->proxy->upstream.connection); | |
1005 } | |
1006 | |
1007 ngx_mail_session_internal_server_error(s); | |
1008 } | |
1009 | |
1010 | |
1011 static void | |
1012 ngx_mail_proxy_close_session(ngx_mail_session_t *s) | |
1013 { | |
1014 if (s->proxy->upstream.connection) { | |
1015 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, | |
1016 "close mail proxy connection: %d", | |
1017 s->proxy->upstream.connection->fd); | |
1018 | |
1019 ngx_close_connection(s->proxy->upstream.connection); | |
1020 } | |
1021 | |
1022 ngx_mail_close_connection(s->connection); | |
1023 } | |
1024 | |
1025 | |
1026 static void * | |
1027 ngx_mail_proxy_create_conf(ngx_conf_t *cf) | |
1028 { | |
1029 ngx_mail_proxy_conf_t *pcf; | |
1030 | |
1031 pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t)); | |
1032 if (pcf == NULL) { | |
1033 return NGX_CONF_ERROR; | |
1034 } | |
1035 | |
1036 pcf->enable = NGX_CONF_UNSET; | |
1037 pcf->pass_error_message = NGX_CONF_UNSET; | |
1038 pcf->xclient = NGX_CONF_UNSET; | |
1039 pcf->buffer_size = NGX_CONF_UNSET_SIZE; | |
1040 pcf->timeout = NGX_CONF_UNSET_MSEC; | |
1041 | |
1042 return pcf; | |
1043 } | |
1044 | |
1045 | |
1046 static char * | |
1047 ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
1048 { | |
1049 ngx_mail_proxy_conf_t *prev = parent; | |
1050 ngx_mail_proxy_conf_t *conf = child; | |
1051 | |
1052 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
1053 ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0); | |
1054 ngx_conf_merge_value(conf->xclient, prev->xclient, 1); | |
1055 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, | |
1056 (size_t) ngx_pagesize); | |
1057 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); | |
1058 | |
1059 return NGX_CONF_OK; | |
1060 } |