comparison src/mail/ngx_mail_proxy_module.c @ 7796:4b8f23a36ebf

Mail: sending of the PROXY protocol to backends. Activated with the "proxy_protocol" directive. Can be combined with "listen ... proxy_protocol;" and "set_real_ip_from ...;" to pass client address provided to nginx in the PROXY protocol header.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 05 Mar 2021 17:16:32 +0300
parents da0a85e91587
children c72d8839f427
comparison
equal deleted inserted replaced
7795:ef4bdbbce57e 7796:4b8f23a36ebf
15 typedef struct { 15 typedef struct {
16 ngx_flag_t enable; 16 ngx_flag_t enable;
17 ngx_flag_t pass_error_message; 17 ngx_flag_t pass_error_message;
18 ngx_flag_t xclient; 18 ngx_flag_t xclient;
19 ngx_flag_t smtp_auth; 19 ngx_flag_t smtp_auth;
20 ngx_flag_t proxy_protocol;
20 size_t buffer_size; 21 size_t buffer_size;
21 ngx_msec_t timeout; 22 ngx_msec_t timeout;
22 } ngx_mail_proxy_conf_t; 23 } ngx_mail_proxy_conf_t;
23 24
24 25
25 static void ngx_mail_proxy_block_read(ngx_event_t *rev); 26 static void ngx_mail_proxy_block_read(ngx_event_t *rev);
26 static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev); 27 static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
27 static void ngx_mail_proxy_imap_handler(ngx_event_t *rev); 28 static void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
28 static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev); 29 static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
29 static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev); 30 static void ngx_mail_proxy_write_handler(ngx_event_t *wev);
31 static ngx_int_t ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s);
30 static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s, 32 static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
31 ngx_uint_t state); 33 ngx_uint_t state);
32 static void ngx_mail_proxy_handler(ngx_event_t *ev); 34 static void ngx_mail_proxy_handler(ngx_event_t *ev);
33 static void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s); 35 static void ngx_mail_proxy_upstream_error(ngx_mail_session_t *s);
34 static void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s); 36 static void ngx_mail_proxy_internal_server_error(ngx_mail_session_t *s);
78 { ngx_string("proxy_smtp_auth"), 80 { ngx_string("proxy_smtp_auth"),
79 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, 81 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
80 ngx_conf_set_flag_slot, 82 ngx_conf_set_flag_slot,
81 NGX_MAIL_SRV_CONF_OFFSET, 83 NGX_MAIL_SRV_CONF_OFFSET,
82 offsetof(ngx_mail_proxy_conf_t, smtp_auth), 84 offsetof(ngx_mail_proxy_conf_t, smtp_auth),
85 NULL },
86
87 { ngx_string("proxy_protocol"),
88 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
89 ngx_conf_set_flag_slot,
90 NGX_MAIL_SRV_CONF_OFFSET,
91 offsetof(ngx_mail_proxy_conf_t, proxy_protocol),
83 NULL }, 92 NULL },
84 93
85 ngx_null_command 94 ngx_null_command
86 }; 95 };
87 96
154 163
155 p->upstream.connection->data = s; 164 p->upstream.connection->data = s;
156 p->upstream.connection->pool = s->connection->pool; 165 p->upstream.connection->pool = s->connection->pool;
157 166
158 s->connection->read->handler = ngx_mail_proxy_block_read; 167 s->connection->read->handler = ngx_mail_proxy_block_read;
159 p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler; 168 p->upstream.connection->write->handler = ngx_mail_proxy_write_handler;
160 169
161 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); 170 pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
162 171
163 s->proxy->buffer = ngx_create_temp_buf(s->connection->pool, 172 s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
164 pcf->buffer_size); 173 pcf->buffer_size);
165 if (s->proxy->buffer == NULL) { 174 if (s->proxy->buffer == NULL) {
166 ngx_mail_proxy_internal_server_error(s); 175 ngx_mail_proxy_internal_server_error(s);
167 return; 176 return;
168 } 177 }
169 178
179 s->proxy->proxy_protocol = pcf->proxy_protocol;
180
170 s->out.len = 0; 181 s->out.len = 0;
171 182
172 switch (s->protocol) { 183 switch (s->protocol) {
173 184
174 case NGX_MAIL_POP3_PROTOCOL: 185 case NGX_MAIL_POP3_PROTOCOL:
184 default: /* NGX_MAIL_SMTP_PROTOCOL */ 195 default: /* NGX_MAIL_SMTP_PROTOCOL */
185 p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler; 196 p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
186 s->mail_state = ngx_smtp_start; 197 s->mail_state = ngx_smtp_start;
187 break; 198 break;
188 } 199 }
200
201 if (rc == NGX_AGAIN) {
202 return;
203 }
204
205 ngx_mail_proxy_write_handler(p->upstream.connection->write);
189 } 206 }
190 207
191 208
192 static void 209 static void
193 ngx_mail_proxy_block_read(ngx_event_t *rev) 210 ngx_mail_proxy_block_read(ngx_event_t *rev)
228 c->timedout = 1; 245 c->timedout = 1;
229 ngx_mail_proxy_internal_server_error(s); 246 ngx_mail_proxy_internal_server_error(s);
230 return; 247 return;
231 } 248 }
232 249
250 if (s->proxy->proxy_protocol) {
251 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy pop3 busy");
252
253 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
254 ngx_mail_proxy_internal_server_error(s);
255 return;
256 }
257
258 return;
259 }
260
233 rc = ngx_mail_proxy_read_response(s, 0); 261 rc = ngx_mail_proxy_read_response(s, 0);
234 262
235 if (rc == NGX_AGAIN) { 263 if (rc == NGX_AGAIN) {
236 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 264 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
237 ngx_mail_proxy_internal_server_error(s); 265 ngx_mail_proxy_internal_server_error(s);
348 if (rev->timedout) { 376 if (rev->timedout) {
349 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, 377 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
350 "upstream timed out"); 378 "upstream timed out");
351 c->timedout = 1; 379 c->timedout = 1;
352 ngx_mail_proxy_internal_server_error(s); 380 ngx_mail_proxy_internal_server_error(s);
381 return;
382 }
383
384 if (s->proxy->proxy_protocol) {
385 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy imap busy");
386
387 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
388 ngx_mail_proxy_internal_server_error(s);
389 return;
390 }
391
353 return; 392 return;
354 } 393 }
355 394
356 rc = ngx_mail_proxy_read_response(s, s->mail_state); 395 rc = ngx_mail_proxy_read_response(s, s->mail_state);
357 396
497 c->timedout = 1; 536 c->timedout = 1;
498 ngx_mail_proxy_internal_server_error(s); 537 ngx_mail_proxy_internal_server_error(s);
499 return; 538 return;
500 } 539 }
501 540
541 if (s->proxy->proxy_protocol) {
542 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy smtp busy");
543
544 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
545 ngx_mail_proxy_internal_server_error(s);
546 return;
547 }
548
549 return;
550 }
551
502 rc = ngx_mail_proxy_read_response(s, s->mail_state); 552 rc = ngx_mail_proxy_read_response(s, s->mail_state);
503 553
504 if (rc == NGX_AGAIN) { 554 if (rc == NGX_AGAIN) {
505 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 555 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
506 ngx_mail_proxy_internal_server_error(s); 556 ngx_mail_proxy_internal_server_error(s);
797 s->proxy->buffer->last = s->proxy->buffer->start; 847 s->proxy->buffer->last = s->proxy->buffer->start;
798 } 848 }
799 849
800 850
801 static void 851 static void
802 ngx_mail_proxy_dummy_handler(ngx_event_t *wev) 852 ngx_mail_proxy_write_handler(ngx_event_t *wev)
803 { 853 {
804 ngx_connection_t *c; 854 ngx_connection_t *c;
805 ngx_mail_session_t *s; 855 ngx_mail_session_t *s;
806 856
807 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy dummy handler"); 857 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy write handler");
858
859 c = wev->data;
860 s = c->data;
861
862 if (s->proxy->proxy_protocol) {
863 if (ngx_mail_proxy_send_proxy_protocol(s) != NGX_OK) {
864 return;
865 }
866
867 s->proxy->proxy_protocol = 0;
868 }
808 869
809 if (ngx_handle_write_event(wev, 0) != NGX_OK) { 870 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
810 c = wev->data; 871 ngx_mail_proxy_internal_server_error(s);
811 s = c->data; 872 }
812 873
813 ngx_mail_proxy_close_session(s); 874 if (c->read->ready) {
814 } 875 ngx_post_event(c->read, &ngx_posted_events);
876 }
877 }
878
879
880 static ngx_int_t
881 ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s)
882 {
883 u_char *p;
884 ssize_t n, size;
885 ngx_connection_t *c;
886 u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
887
888 s->connection->log->action = "sending PROXY protocol header to upstream";
889
890 ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
891 "mail proxy send PROXY protocol header");
892
893 p = ngx_proxy_protocol_write(s->connection, buf,
894 buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
895 if (p == NULL) {
896 ngx_mail_proxy_internal_server_error(s);
897 return NGX_ERROR;
898 }
899
900 c = s->proxy->upstream.connection;
901
902 size = p - buf;
903
904 n = c->send(c, buf, size);
905
906 if (n == NGX_AGAIN) {
907 if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
908 ngx_mail_proxy_internal_server_error(s);
909 return NGX_ERROR;
910 }
911
912 return NGX_AGAIN;
913 }
914
915 if (n == NGX_ERROR) {
916 ngx_mail_proxy_internal_server_error(s);
917 return NGX_ERROR;
918 }
919
920 if (n != size) {
921
922 /*
923 * PROXY protocol specification:
924 * The sender must always ensure that the header
925 * is sent at once, so that the transport layer
926 * maintains atomicity along the path to the receiver.
927 */
928
929 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
930 "could not send PROXY protocol header at once");
931
932 ngx_mail_proxy_internal_server_error(s);
933
934 return NGX_ERROR;
935 }
936
937 return NGX_OK;
815 } 938 }
816 939
817 940
818 static ngx_int_t 941 static ngx_int_t
819 ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state) 942 ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
1210 1333
1211 pcf->enable = NGX_CONF_UNSET; 1334 pcf->enable = NGX_CONF_UNSET;
1212 pcf->pass_error_message = NGX_CONF_UNSET; 1335 pcf->pass_error_message = NGX_CONF_UNSET;
1213 pcf->xclient = NGX_CONF_UNSET; 1336 pcf->xclient = NGX_CONF_UNSET;
1214 pcf->smtp_auth = NGX_CONF_UNSET; 1337 pcf->smtp_auth = NGX_CONF_UNSET;
1338 pcf->proxy_protocol = NGX_CONF_UNSET;
1215 pcf->buffer_size = NGX_CONF_UNSET_SIZE; 1339 pcf->buffer_size = NGX_CONF_UNSET_SIZE;
1216 pcf->timeout = NGX_CONF_UNSET_MSEC; 1340 pcf->timeout = NGX_CONF_UNSET_MSEC;
1217 1341
1218 return pcf; 1342 return pcf;
1219 } 1343 }
1227 1351
1228 ngx_conf_merge_value(conf->enable, prev->enable, 0); 1352 ngx_conf_merge_value(conf->enable, prev->enable, 0);
1229 ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0); 1353 ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0);
1230 ngx_conf_merge_value(conf->xclient, prev->xclient, 1); 1354 ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
1231 ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0); 1355 ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0);
1356 ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0);
1232 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 1357 ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
1233 (size_t) ngx_pagesize); 1358 (size_t) ngx_pagesize);
1234 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); 1359 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);
1235 1360
1236 return NGX_CONF_OK; 1361 return NGX_CONF_OK;