Mercurial > hg > nginx
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; |