Klaus Demo nginx / 711c36b
smtp_client_buffer and smtp_greeting_delay Igor Sysoev 14 years ago
3 changed file(s) with 209 addition(s) and 76 deletion(s). Raw diff Collapse all Expand all
7474
7575 typedef struct {
7676 ngx_msec_t timeout;
77 ngx_msec_t smtp_greeting_delay;
7778
7879 size_t imap_client_buffer_size;
80 size_t smtp_client_buffer_size;
7981
8082 ngx_uint_t protocol;
8183
129129 ngx_conf_set_size_slot,
130130 NGX_MAIL_SRV_CONF_OFFSET,
131131 offsetof(ngx_mail_core_srv_conf_t, imap_client_buffer_size),
132 NULL },
133
134 { ngx_string("smtp_client_buffer"),
135 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
136 ngx_conf_set_size_slot,
137 NGX_MAIL_SRV_CONF_OFFSET,
138 offsetof(ngx_mail_core_srv_conf_t, smtp_client_buffer_size),
139 NULL },
140
141 { ngx_string("smtp_greeting_delay"),
142 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
143 ngx_conf_set_msec_slot,
144 NGX_MAIL_SRV_CONF_OFFSET,
145 offsetof(ngx_mail_core_srv_conf_t, smtp_greeting_delay),
132146 NULL },
133147
134148 { ngx_string("so_keepalive"),
268282 }
269283
270284 cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE;
285 cscf->smtp_client_buffer_size = NGX_CONF_UNSET_SIZE;
271286 cscf->protocol = NGX_CONF_UNSET_UINT;
272287 cscf->timeout = NGX_CONF_UNSET_MSEC;
288 cscf->smtp_greeting_delay = NGX_CONF_UNSET_MSEC;
273289 cscf->so_keepalive = NGX_CONF_UNSET;
274290
275291 if (ngx_array_init(&cscf->pop3_capabilities, cf->pool, 4, sizeof(ngx_str_t))
308324 ngx_conf_merge_size_value(conf->imap_client_buffer_size,
309325 prev->imap_client_buffer_size,
310326 (size_t) ngx_pagesize);
327 ngx_conf_merge_size_value(conf->smtp_client_buffer_size,
328 prev->smtp_client_buffer_size,
329 (size_t) ngx_pagesize);
330
311331 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
332 ngx_conf_merge_msec_value(conf->smtp_greeting_delay,
333 prev->smtp_greeting_delay, 0);
334
312335 ngx_conf_merge_uint_value(conf->protocol, prev->protocol,
313336 NGX_MAIL_IMAP_PROTOCOL);
314337 ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
315338
316
317339 ngx_conf_merge_bitmask_value(conf->pop3_auth_methods,
318 prev->pop3_auth_methods,
319 (NGX_CONF_BITMASK_SET
320 |NGX_MAIL_AUTH_PLAIN_ENABLED));
340 prev->pop3_auth_methods,
341 (NGX_CONF_BITMASK_SET
342 |NGX_MAIL_AUTH_PLAIN_ENABLED));
321343
322344 ngx_conf_merge_bitmask_value(conf->imap_auth_methods,
323 prev->imap_auth_methods,
324 (NGX_CONF_BITMASK_SET
325 |NGX_MAIL_AUTH_PLAIN_ENABLED));
345 prev->imap_auth_methods,
346 (NGX_CONF_BITMASK_SET
347 |NGX_MAIL_AUTH_PLAIN_ENABLED));
326348
327349 ngx_conf_merge_bitmask_value(conf->smtp_auth_methods,
328 prev->smtp_auth_methods,
329 (NGX_CONF_BITMASK_SET
330 |NGX_MAIL_AUTH_PLAIN_ENABLED
331 |NGX_MAIL_AUTH_LOGIN_ENABLED));
350 prev->smtp_auth_methods,
351 (NGX_CONF_BITMASK_SET
352 |NGX_MAIL_AUTH_PLAIN_ENABLED
353 |NGX_MAIL_AUTH_LOGIN_ENABLED));
332354
333355
334356 ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
88 #include <ngx_event.h>
99 #include <ngx_mail.h>
1010
11
12 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
1113
1214 static ngx_int_t ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c);
1315 static ngx_int_t ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c);
1416 static ngx_int_t ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c);
1517 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
1618 ngx_connection_t *c);
19
20 static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
21 ngx_connection_t *c, char *err);
22 static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
23 ngx_connection_t *c, char *err);
1724
1825
1926 static u_char smtp_ok[] = "250 2.0.0 OK" CRLF;
2229 static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
2330 static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
2431 static u_char smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
32 static u_char smtp_invalid_pipelining[] =
33 "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
2534 static u_char smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
2635 static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
2736
2938 void
3039 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
3140 {
41 ngx_msec_t timeout;
3242 ngx_mail_core_srv_conf_t *cscf;
3343
3444 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
3949 return;
4050 }
4151 }
42
43 s->out = cscf->smtp_greeting;
44
45 c->read->handler = ngx_mail_smtp_init_protocol;
46
47 ngx_add_timer(c->read, cscf->timeout);
48
49 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
50 ngx_mail_close_connection(c);
51 }
52
53 ngx_mail_send(c->write);
54 }
55
56
57 void
58 ngx_mail_smtp_init_protocol(ngx_event_t *rev)
59 {
60 ngx_connection_t *c;
61 ngx_mail_session_t *s;
62
63 c = rev->data;
64
65 c->log->action = "in auth state";
66
67 if (rev->timedout) {
68 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
69 c->timedout = 1;
70 ngx_mail_close_connection(c);
71 return;
72 }
73
74 s = c->data;
7552
7653 if (s->buffer == NULL) {
7754 if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
8158 return;
8259 }
8360
84 s->buffer = ngx_create_temp_buf(c->pool, 512);
61 s->buffer = ngx_create_temp_buf(c->pool, cscf->smtp_client_buffer_size);
8562 if (s->buffer == NULL) {
8663 ngx_mail_session_internal_server_error(s);
8764 return;
8865 }
8966 }
67
68 timeout = cscf->smtp_greeting_delay ? cscf->smtp_greeting_delay:
69 cscf->timeout;
70 ngx_add_timer(c->read, timeout);
71
72 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
73 ngx_mail_close_connection(c);
74 }
75
76 if (cscf->smtp_greeting_delay) {
77 c->read->handler = ngx_mail_smtp_invalid_pipelining;
78 return;
79 }
80
81 c->read->handler = ngx_mail_smtp_init_protocol;
82
83 s->out = cscf->smtp_greeting;
84
85 ngx_mail_send(c->write);
86 }
87
88
89 static void
90 ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
91 {
92 ngx_connection_t *c;
93 ngx_mail_session_t *s;
94 ngx_mail_core_srv_conf_t *cscf;
95
96 c = rev->data;
97 s = c->data;
98
99 c->log->action = "in delay pipelining state";
100
101 if (rev->timedout) {
102
103 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");
104
105 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
106
107 c->read->handler = ngx_mail_smtp_init_protocol;
108
109 ngx_add_timer(c->read, cscf->timeout);
110
111 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
112 ngx_mail_close_connection(c);
113 return;
114 }
115
116 s->out = cscf->smtp_greeting;
117
118 } else {
119
120 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");
121
122 if (ngx_mail_smtp_discard_command(s, c,
123 "client was rejected before greeting: \"%V\"")
124 != NGX_OK)
125 {
126 return;
127 }
128
129 s->out.len = sizeof(smtp_invalid_pipelining) - 1;
130 s->out.data = smtp_invalid_pipelining;
131 }
132
133 ngx_mail_send(c->write);
134 }
135
136
137 void
138 ngx_mail_smtp_init_protocol(ngx_event_t *rev)
139 {
140 ngx_connection_t *c;
141 ngx_mail_session_t *s;
142
143 c = rev->data;
144
145 c->log->action = "in auth state";
146
147 if (rev->timedout) {
148 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
149 c->timedout = 1;
150 ngx_mail_close_connection(c);
151 return;
152 }
153
154 s = c->data;
90155
91156 s->mail_state = ngx_smtp_start;
92157 c->read->handler = ngx_mail_smtp_auth_state;
348413 static ngx_int_t
349414 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
350415 {
351 u_char ch;
352 ngx_str_t mail;
353 ngx_uint_t i;
354
355 if (c->log->log_level >= NGX_LOG_INFO) {
356 mail.len = s->buffer->last - s->buffer->start;
357 mail.data = s->buffer->start;
358
359 for (i = 0; i < mail.len; i++) {
360 ch = mail.data[i];
361
362 if (ch != CR && ch != LF) {
363 continue;
364 }
365
366 mail.data[i] = ' ';
367 }
368
369 while (i) {
370 if (mail.data[i - 1] != ' ') {
371 break;
372 }
373
374 i--;
375 }
376
377 mail.len = i;
378
379 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
380 "client was rejected: \"%V\"", &mail);
381 }
416 ngx_mail_smtp_log_rejected_command(s, c, "client was rejected: \"%V\"");
382417
383418 s->out.len = sizeof(smtp_auth_required) - 1;
384419 s->out.data = smtp_auth_required;
414449
415450 return NGX_MAIL_PARSE_INVALID_COMMAND;
416451 }
452
453
454 static ngx_int_t
455 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
456 char *err)
457 {
458 ssize_t n;
459
460 n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
461
462 if (n == NGX_ERROR || n == 0) {
463 ngx_mail_close_connection(c);
464 return NGX_ERROR;
465 }
466
467 if (n > 0) {
468 s->buffer->last += n;
469 }
470
471 if (n == NGX_AGAIN) {
472 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
473 ngx_mail_session_internal_server_error(s);
474 return NGX_ERROR;
475 }
476
477 return NGX_AGAIN;
478 }
479
480 ngx_mail_smtp_log_rejected_command(s, c, err);
481
482 s->buffer->pos = s->buffer->start;
483 s->buffer->last = s->buffer->start;
484
485 return NGX_OK;
486 }
487
488
489 static void
490 ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
491 char *err)
492 {
493 u_char ch;
494 ngx_str_t cmd;
495 ngx_uint_t i;
496
497 if (c->log->log_level < NGX_LOG_INFO) {
498 return;
499 }
500
501 cmd.len = s->buffer->last - s->buffer->start;
502 cmd.data = s->buffer->start;
503
504 for (i = 0; i < cmd.len; i++) {
505 ch = cmd.data[i];
506
507 if (ch != CR && ch != LF) {
508 continue;
509 }
510
511 cmd.data[i] = ' ';
512 }
513
514 while (i) {
515 if (cmd.data[i - 1] != ' ') {
516 break;
517 }
518
519 i--;
520 }
521
522 cmd.len = i;
523
524 ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
525 }