Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_mail_proxy_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_event_connect.h>
12 #include <ngx_mail.h>
13 
14 
15 typedef struct {
19  size_t buffer_size;
22 
23 
24 static void ngx_mail_proxy_block_read(ngx_event_t *rev);
25 static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
26 static void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
27 static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
28 static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev);
29 static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
30  ngx_uint_t state);
31 static void ngx_mail_proxy_handler(ngx_event_t *ev);
32 static void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s);
33 static void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s);
34 static void ngx_mail_proxy_close_session(ngx_mail_session_t *s);
35 static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
36 static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
37  void *child);
38 
39 
40 static ngx_command_t ngx_mail_proxy_commands[] = {
41 
42  { ngx_string("proxy"),
46  offsetof(ngx_mail_proxy_conf_t, enable),
47  NULL },
48 
49  { ngx_string("proxy_buffer"),
53  offsetof(ngx_mail_proxy_conf_t, buffer_size),
54  NULL },
55 
56  { ngx_string("proxy_timeout"),
60  offsetof(ngx_mail_proxy_conf_t, timeout),
61  NULL },
62 
63  { ngx_string("proxy_pass_error_message"),
67  offsetof(ngx_mail_proxy_conf_t, pass_error_message),
68  NULL },
69 
70  { ngx_string("xclient"),
74  offsetof(ngx_mail_proxy_conf_t, xclient),
75  NULL },
76 
78 };
79 
80 
81 static ngx_mail_module_t ngx_mail_proxy_module_ctx = {
82  NULL, /* protocol */
83 
84  NULL, /* create main configuration */
85  NULL, /* init main configuration */
86 
87  ngx_mail_proxy_create_conf, /* create server configuration */
88  ngx_mail_proxy_merge_conf /* merge server configuration */
89 };
90 
91 
94  &ngx_mail_proxy_module_ctx, /* module context */
95  ngx_mail_proxy_commands, /* module directives */
96  NGX_MAIL_MODULE, /* module type */
97  NULL, /* init master */
98  NULL, /* init module */
99  NULL, /* init process */
100  NULL, /* init thread */
101  NULL, /* exit thread */
102  NULL, /* exit process */
103  NULL, /* exit master */
105 };
106 
107 
108 static u_char smtp_auth_ok[] = "235 2.0.0 OK" CRLF;
109 
110 
111 void
113 {
114  int keepalive;
115  ngx_int_t rc;
119 
120  s->connection->log->action = "connecting to upstream";
121 
123 
124  if (cscf->so_keepalive) {
125  keepalive = 1;
126 
127  if (setsockopt(s->connection->fd, SOL_SOCKET, SO_KEEPALIVE,
128  (const void *) &keepalive, sizeof(int))
129  == -1)
130  {
132  "setsockopt(SO_KEEPALIVE) failed");
133  }
134  }
135 
137  if (p == NULL) {
139  return;
140  }
141 
142  s->proxy = p;
143 
144  p->upstream.sockaddr = peer->sockaddr;
145  p->upstream.socklen = peer->socklen;
146  p->upstream.name = &peer->name;
148  p->upstream.log = s->connection->log;
150 
152 
153  if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
154  ngx_mail_proxy_internal_server_error(s);
155  return;
156  }
157 
159 
160  p->upstream.connection->data = s;
162 
163  s->connection->read->handler = ngx_mail_proxy_block_read;
164  p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;
165 
166  pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
167 
169  pcf->buffer_size);
170  if (s->proxy->buffer == NULL) {
171  ngx_mail_proxy_internal_server_error(s);
172  return;
173  }
174 
175  s->out.len = 0;
176 
177  switch (s->protocol) {
178 
180  p->upstream.connection->read->handler = ngx_mail_proxy_pop3_handler;
182  break;
183 
185  p->upstream.connection->read->handler = ngx_mail_proxy_imap_handler;
187  break;
188 
189  default: /* NGX_MAIL_SMTP_PROTOCOL */
190  p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
192  break;
193  }
194 }
195 
196 
197 static void
198 ngx_mail_proxy_block_read(ngx_event_t *rev)
199 {
200  ngx_connection_t *c;
202 
203  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy block read");
204 
205  if (ngx_handle_read_event(rev, 0) != NGX_OK) {
206  c = rev->data;
207  s = c->data;
208 
209  ngx_mail_proxy_close_session(s);
210  }
211 }
212 
213 
214 static void
215 ngx_mail_proxy_pop3_handler(ngx_event_t *rev)
216 {
217  u_char *p;
218  ngx_int_t rc;
219  ngx_str_t line;
220  ngx_connection_t *c;
223 
225  "mail proxy pop3 auth handler");
226 
227  c = rev->data;
228  s = c->data;
229 
230  if (rev->timedout) {
232  "upstream timed out");
233  c->timedout = 1;
234  ngx_mail_proxy_internal_server_error(s);
235  return;
236  }
237 
238  rc = ngx_mail_proxy_read_response(s, 0);
239 
240  if (rc == NGX_AGAIN) {
241  return;
242  }
243 
244  if (rc == NGX_ERROR) {
245  ngx_mail_proxy_upstream_error(s);
246  return;
247  }
248 
249  switch (s->mail_state) {
250 
251  case ngx_pop3_start:
252  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");
253 
254  s->connection->log->action = "sending user name to upstream";
255 
256  line.len = sizeof("USER ") - 1 + s->login.len + 2;
257  line.data = ngx_pnalloc(c->pool, line.len);
258  if (line.data == NULL) {
259  ngx_mail_proxy_internal_server_error(s);
260  return;
261  }
262 
263  p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
264  p = ngx_cpymem(p, s->login.data, s->login.len);
265  *p++ = CR; *p = LF;
266 
268  break;
269 
270  case ngx_pop3_user:
271  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send pass");
272 
273  s->connection->log->action = "sending password to upstream";
274 
275  line.len = sizeof("PASS ") - 1 + s->passwd.len + 2;
276  line.data = ngx_pnalloc(c->pool, line.len);
277  if (line.data == NULL) {
278  ngx_mail_proxy_internal_server_error(s);
279  return;
280  }
281 
282  p = ngx_cpymem(line.data, "PASS ", sizeof("PASS ") - 1);
283  p = ngx_cpymem(p, s->passwd.data, s->passwd.len);
284  *p++ = CR; *p = LF;
285 
287  break;
288 
289  case ngx_pop3_passwd:
290  s->connection->read->handler = ngx_mail_proxy_handler;
291  s->connection->write->handler = ngx_mail_proxy_handler;
292  rev->handler = ngx_mail_proxy_handler;
293  c->write->handler = ngx_mail_proxy_handler;
294 
295  pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
297  ngx_del_timer(c->read);
298 
299  c->log->action = NULL;
300  ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
301 
302  ngx_mail_proxy_handler(s->connection->write);
303 
304  return;
305 
306  default:
307 #if (NGX_SUPPRESS_WARN)
308  ngx_str_null(&line);
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;
336 
338  "mail proxy imap auth handler");
339 
340  c = rev->data;
341  s = c->data;
342 
343  if (rev->timedout) {
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:
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;
372  line.data = ngx_pnalloc(c->pool, line.len);
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 
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;
391  line.data = ngx_pnalloc(c->pool, line.len);
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 
402  break;
403 
404  case ngx_imap_user:
406  "mail proxy send passwd");
407 
408  s->connection->log->action = "sending password to upstream";
409 
410  line.len = s->passwd.len + 2;
411  line.data = ngx_pnalloc(c->pool, line.len);
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 
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);
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  ngx_str_null(&line);
443 #endif
444  break;
445  }
446 
447  if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
448  /*
449  * we treat the incomplete sending as NGX_ERROR
450  * because it is very strange here
451  */
452  ngx_mail_proxy_internal_server_error(s);
453  return;
454  }
455 
456  s->proxy->buffer->pos = s->proxy->buffer->start;
457  s->proxy->buffer->last = s->proxy->buffer->start;
458 }
459 
460 
461 static void
462 ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
463 {
464  u_char *p;
465  ngx_int_t rc;
466  ngx_str_t line;
467  ngx_buf_t *b;
468  ngx_connection_t *c;
472 
474  "mail proxy smtp auth handler");
475 
476  c = rev->data;
477  s = c->data;
478 
479  if (rev->timedout) {
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 
506 
507  line.len = sizeof("HELO ") - 1 + cscf->server_name.len + 2;
508  line.data = ngx_pnalloc(c->pool, line.len);
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 
523  if (pcf->xclient) {
525 
526  } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
528 
529  } else {
531  }
532 
533  break;
534 
537  "mail proxy send xclient");
538 
539  s->connection->log->action = "sending XCLIENT to upstream";
540 
541  line.len = sizeof("XCLIENT ADDR= LOGIN= NAME="
542  CRLF) - 1
543  + s->connection->addr_text.len + s->login.len + s->host.len;
544 
545  line.data = ngx_pnalloc(c->pool, line.len);
546  if (line.data == NULL) {
547  ngx_mail_proxy_internal_server_error(s);
548  return;
549  }
550 
551  line.len = ngx_sprintf(line.data,
552  "XCLIENT ADDR=%V%s%V NAME=%V" CRLF,
553  &s->connection->addr_text,
554  (s->login.len ? " LOGIN=" : ""), &s->login, &s->host)
555  - line.data;
556 
557  if (s->smtp_helo.len) {
559 
560  } else if (s->auth_method == NGX_MAIL_AUTH_NONE) {
562 
563  } else {
565  }
566 
567  break;
568 
571  "mail proxy send client ehlo");
572 
573  s->connection->log->action = "sending client HELO/EHLO to upstream";
574 
575  line.len = sizeof("HELO " CRLF) - 1 + s->smtp_helo.len;
576 
577  line.data = ngx_pnalloc(c->pool, line.len);
578  if (line.data == NULL) {
579  ngx_mail_proxy_internal_server_error(s);
580  return;
581  }
582 
583  line.len = ngx_sprintf(line.data,
584  ((s->esmtp) ? "EHLO %V" CRLF : "HELO %V" CRLF),
585  &s->smtp_helo)
586  - line.data;
587 
590 
591  break;
592 
593  case ngx_smtp_helo_from:
596  "mail proxy send mail from");
597 
598  s->connection->log->action = "sending MAIL FROM to upstream";
599 
600  line.len = s->smtp_from.len + sizeof(CRLF) - 1;
601  line.data = ngx_pnalloc(c->pool, line.len);
602  if (line.data == NULL) {
603  ngx_mail_proxy_internal_server_error(s);
604  return;
605  }
606 
607  p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len);
608  *p++ = CR; *p = LF;
609 
611 
612  break;
613 
614  case ngx_smtp_from:
616  "mail proxy send rcpt to");
617 
618  s->connection->log->action = "sending RCPT TO to upstream";
619 
620  line.len = s->smtp_to.len + sizeof(CRLF) - 1;
621  line.data = ngx_pnalloc(c->pool, line.len);
622  if (line.data == NULL) {
623  ngx_mail_proxy_internal_server_error(s);
624  return;
625  }
626 
627  p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len);
628  *p++ = CR; *p = LF;
629 
630  s->mail_state = ngx_smtp_to;
631 
632  break;
633 
634  case ngx_smtp_helo:
635  case ngx_smtp_xclient:
636  case ngx_smtp_to:
637 
638  b = s->proxy->buffer;
639 
640  if (s->auth_method == NGX_MAIL_AUTH_NONE) {
641  b->pos = b->start;
642 
643  } else {
644  ngx_memcpy(b->start, smtp_auth_ok, sizeof(smtp_auth_ok) - 1);
645  b->last = b->start + sizeof(smtp_auth_ok) - 1;
646  }
647 
648  s->connection->read->handler = ngx_mail_proxy_handler;
649  s->connection->write->handler = ngx_mail_proxy_handler;
650  rev->handler = ngx_mail_proxy_handler;
651  c->write->handler = ngx_mail_proxy_handler;
652 
653  pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
655  ngx_del_timer(c->read);
656 
657  c->log->action = NULL;
658  ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
659 
660  ngx_mail_proxy_handler(s->connection->write);
661 
662  return;
663 
664  default:
665 #if (NGX_SUPPRESS_WARN)
666  ngx_str_null(&line);
667 #endif
668  break;
669  }
670 
671  if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
672  /*
673  * we treat the incomplete sending as NGX_ERROR
674  * because it is very strange here
675  */
676  ngx_mail_proxy_internal_server_error(s);
677  return;
678  }
679 
680  s->proxy->buffer->pos = s->proxy->buffer->start;
681  s->proxy->buffer->last = s->proxy->buffer->start;
682 }
683 
684 
685 static void
686 ngx_mail_proxy_dummy_handler(ngx_event_t *wev)
687 {
688  ngx_connection_t *c;
690 
691  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy dummy handler");
692 
693  if (ngx_handle_write_event(wev, 0) != NGX_OK) {
694  c = wev->data;
695  s = c->data;
696 
697  ngx_mail_proxy_close_session(s);
698  }
699 }
700 
701 
702 static ngx_int_t
703 ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
704 {
705  u_char *p;
706  ssize_t n;
707  ngx_buf_t *b;
709 
710  s->connection->log->action = "reading response from upstream";
711 
712  b = s->proxy->buffer;
713 
715  b->last, b->end - b->last);
716 
717  if (n == NGX_ERROR || n == 0) {
718  return NGX_ERROR;
719  }
720 
721  if (n == NGX_AGAIN) {
722  return NGX_AGAIN;
723  }
724 
725  b->last += n;
726 
727  if (b->last - b->pos < 4) {
728  return NGX_AGAIN;
729  }
730 
731  if (*(b->last - 2) != CR || *(b->last - 1) != LF) {
732  if (b->last == b->end) {
733  *(b->last - 1) = '\0';
735  "upstream sent too long response line: \"%s\"",
736  b->pos);
737  return NGX_ERROR;
738  }
739 
740  return NGX_AGAIN;
741  }
742 
743  p = b->pos;
744 
745  switch (s->protocol) {
746 
748  if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
749  return NGX_OK;
750  }
751  break;
752 
754  switch (state) {
755 
756  case ngx_imap_start:
757  if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
758  return NGX_OK;
759  }
760  break;
761 
762  case ngx_imap_login:
763  case ngx_imap_user:
764  if (p[0] == '+') {
765  return NGX_OK;
766  }
767  break;
768 
769  case ngx_imap_passwd:
770  if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) {
771  p += s->tag.len;
772  if (p[0] == 'O' && p[1] == 'K') {
773  return NGX_OK;
774  }
775  }
776  break;
777  }
778 
779  break;
780 
781  default: /* NGX_MAIL_SMTP_PROTOCOL */
782  switch (state) {
783 
784  case ngx_smtp_start:
785  if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
786  return NGX_OK;
787  }
788  break;
789 
790  case ngx_smtp_helo:
792  case ngx_smtp_helo_from:
793  case ngx_smtp_from:
794  if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
795  return NGX_OK;
796  }
797  break;
798 
799  case ngx_smtp_xclient:
802  if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') {
803  return NGX_OK;
804  }
805  break;
806 
807  case ngx_smtp_to:
808  return NGX_OK;
809  }
810 
811  break;
812  }
813 
814  pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
815 
816  if (pcf->pass_error_message == 0) {
817  *(b->last - 2) = '\0';
819  "upstream sent invalid response: \"%s\"", p);
820  return NGX_ERROR;
821  }
822 
823  s->out.len = b->last - p - 2;
824  s->out.data = p;
825 
827  "upstream sent invalid response: \"%V\"", &s->out);
828 
829  s->out.len = b->last - b->pos;
830  s->out.data = b->pos;
831 
832  return NGX_ERROR;
833 }
834 
835 
836 static void
837 ngx_mail_proxy_handler(ngx_event_t *ev)
838 {
839  char *action, *recv_action, *send_action;
840  size_t size;
841  ssize_t n;
842  ngx_buf_t *b;
843  ngx_uint_t do_write;
844  ngx_connection_t *c, *src, *dst;
847 
848  c = ev->data;
849  s = c->data;
850 
851  if (ev->timedout) {
852  c->log->action = "proxying";
853 
854  if (c == s->connection) {
856  "client timed out");
857  c->timedout = 1;
858 
859  } else {
861  "upstream timed out");
862  }
863 
864  ngx_mail_proxy_close_session(s);
865  return;
866  }
867 
868  if (c == s->connection) {
869  if (ev->write) {
870  recv_action = "proxying and reading from upstream";
871  send_action = "proxying and sending to client";
872  src = s->proxy->upstream.connection;
873  dst = c;
874  b = s->proxy->buffer;
875 
876  } else {
877  recv_action = "proxying and reading from client";
878  send_action = "proxying and sending to upstream";
879  src = c;
880  dst = s->proxy->upstream.connection;
881  b = s->buffer;
882  }
883 
884  } else {
885  if (ev->write) {
886  recv_action = "proxying and reading from client";
887  send_action = "proxying and sending to upstream";
888  src = s->connection;
889  dst = c;
890  b = s->buffer;
891 
892  } else {
893  recv_action = "proxying and reading from upstream";
894  send_action = "proxying and sending to client";
895  src = c;
896  dst = s->connection;
897  b = s->proxy->buffer;
898  }
899  }
900 
901  do_write = ev->write ? 1 : 0;
902 
904  "mail proxy handler: %d, #%d > #%d",
905  do_write, src->fd, dst->fd);
906 
907  for ( ;; ) {
908 
909  if (do_write) {
910 
911  size = b->last - b->pos;
912 
913  if (size && dst->write->ready) {
914  c->log->action = send_action;
915 
916  n = dst->send(dst, b->pos, size);
917 
918  if (n == NGX_ERROR) {
919  ngx_mail_proxy_close_session(s);
920  return;
921  }
922 
923  if (n > 0) {
924  b->pos += n;
925 
926  if (b->pos == b->last) {
927  b->pos = b->start;
928  b->last = b->start;
929  }
930  }
931  }
932  }
933 
934  size = b->end - b->last;
935 
936  if (size && src->read->ready) {
937  c->log->action = recv_action;
938 
939  n = src->recv(src, b->last, size);
940 
941  if (n == NGX_AGAIN || n == 0) {
942  break;
943  }
944 
945  if (n > 0) {
946  do_write = 1;
947  b->last += n;
948 
949  continue;
950  }
951 
952  if (n == NGX_ERROR) {
953  src->read->eof = 1;
954  }
955  }
956 
957  break;
958  }
959 
960  c->log->action = "proxying";
961 
962  if ((s->connection->read->eof && s->buffer->pos == s->buffer->last)
963  || (s->proxy->upstream.connection->read->eof
964  && s->proxy->buffer->pos == s->proxy->buffer->last)
965  || (s->connection->read->eof
966  && s->proxy->upstream.connection->read->eof))
967  {
968  action = c->log->action;
969  c->log->action = NULL;
970  ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done");
971  c->log->action = action;
972 
973  ngx_mail_proxy_close_session(s);
974  return;
975  }
976 
977  if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
978  ngx_mail_proxy_close_session(s);
979  return;
980  }
981 
982  if (ngx_handle_read_event(dst->read, 0) != NGX_OK) {
983  ngx_mail_proxy_close_session(s);
984  return;
985  }
986 
987  if (ngx_handle_write_event(src->write, 0) != NGX_OK) {
988  ngx_mail_proxy_close_session(s);
989  return;
990  }
991 
992  if (ngx_handle_read_event(src->read, 0) != NGX_OK) {
993  ngx_mail_proxy_close_session(s);
994  return;
995  }
996 
997  if (c == s->connection) {
998  pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
999  ngx_add_timer(c->read, pcf->timeout);
1000  }
1001 }
1002 
1003 
1004 static void
1005 ngx_mail_proxy_upstream_error(ngx_mail_session_t *s)
1006 {
1007  if (s->proxy->upstream.connection) {
1009  "close mail proxy connection: %d",
1010  s->proxy->upstream.connection->fd);
1011 
1013  }
1014 
1015  if (s->out.len == 0) {
1017  return;
1018  }
1019 
1020  s->quit = 1;
1022 }
1023 
1024 
1025 static void
1026 ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s)
1027 {
1028  if (s->proxy->upstream.connection) {
1030  "close mail proxy connection: %d",
1031  s->proxy->upstream.connection->fd);
1032 
1034  }
1035 
1037 }
1038 
1039 
1040 static void
1041 ngx_mail_proxy_close_session(ngx_mail_session_t *s)
1042 {
1043  if (s->proxy->upstream.connection) {
1045  "close mail proxy connection: %d",
1046  s->proxy->upstream.connection->fd);
1047 
1049  }
1050 
1052 }
1053 
1054 
1055 static void *
1056 ngx_mail_proxy_create_conf(ngx_conf_t *cf)
1057 {
1058  ngx_mail_proxy_conf_t *pcf;
1059 
1060  pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t));
1061  if (pcf == NULL) {
1062  return NULL;
1063  }
1064 
1065  pcf->enable = NGX_CONF_UNSET;
1067  pcf->xclient = NGX_CONF_UNSET;
1070 
1071  return pcf;
1072 }
1073 
1074 
1075 static char *
1076 ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child)
1077 {
1078  ngx_mail_proxy_conf_t *prev = parent;
1079  ngx_mail_proxy_conf_t *conf = child;
1080 
1081  ngx_conf_merge_value(conf->enable, prev->enable, 0);
1083  ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
1085  (size_t) ngx_pagesize);
1086  ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);
1087 
1088  return NGX_CONF_OK;
1089 }