mirror of
https://github.com/nginx/nginx.git
synced 2024-11-29 17:29:00 +08:00
Stream: client-side PROXY protocol.
The new directive "proxy_protocol" toggles sending out PROXY protocol header to upstream once connection is established.
This commit is contained in:
parent
f50f83a2cf
commit
3ed1b3b5b0
@ -89,3 +89,52 @@ invalid:
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u_char *
|
||||||
|
ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
|
||||||
|
{
|
||||||
|
ngx_uint_t port, lport;
|
||||||
|
|
||||||
|
if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c->sockaddr->sa_family) {
|
||||||
|
|
||||||
|
case AF_INET:
|
||||||
|
buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
|
||||||
|
|
||||||
|
port = ntohs(((struct sockaddr_in *) c->sockaddr)->sin_port);
|
||||||
|
lport = ntohs(((struct sockaddr_in *) c->local_sockaddr)->sin_port);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_INET6)
|
||||||
|
case AF_INET6:
|
||||||
|
buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
|
||||||
|
|
||||||
|
port = ntohs(((struct sockaddr_in6 *) c->sockaddr)->sin6_port);
|
||||||
|
lport = ntohs(((struct sockaddr_in6 *) c->local_sockaddr)->sin6_port);
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
|
||||||
|
sizeof("PROXY UNKNOWN" CRLF) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
|
||||||
|
|
||||||
|
*buf++ = ' ';
|
||||||
|
|
||||||
|
buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
|
||||||
|
0);
|
||||||
|
|
||||||
|
return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
|
||||||
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf,
|
u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf,
|
||||||
u_char *last);
|
u_char *last);
|
||||||
|
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
|
||||||
|
u_char *last);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
|
||||||
|
@ -21,6 +21,7 @@ typedef struct {
|
|||||||
size_t upstream_buf_size;
|
size_t upstream_buf_size;
|
||||||
ngx_uint_t next_upstream_tries;
|
ngx_uint_t next_upstream_tries;
|
||||||
ngx_flag_t next_upstream;
|
ngx_flag_t next_upstream;
|
||||||
|
ngx_flag_t proxy_protocol;
|
||||||
ngx_addr_t *local;
|
ngx_addr_t *local;
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
@ -67,6 +68,7 @@ static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
|
|||||||
void *conf);
|
void *conf);
|
||||||
static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,
|
static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||||
void *conf);
|
void *conf);
|
||||||
|
static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s);
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
|
|
||||||
@ -156,6 +158,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
|
|||||||
offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout),
|
offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout),
|
||||||
NULL },
|
NULL },
|
||||||
|
|
||||||
|
{ ngx_string("proxy_protocol"),
|
||||||
|
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
|
||||||
|
ngx_conf_set_flag_slot,
|
||||||
|
NGX_STREAM_SRV_CONF_OFFSET,
|
||||||
|
offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol),
|
||||||
|
NULL },
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
|
|
||||||
{ ngx_string("proxy_ssl"),
|
{ ngx_string("proxy_ssl"),
|
||||||
@ -328,6 +337,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s)
|
|||||||
u->peer.tries = pscf->next_upstream_tries;
|
u->peer.tries = pscf->next_upstream_tries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u->proxy_protocol = pscf->proxy_protocol;
|
||||||
|
|
||||||
p = ngx_pnalloc(c->pool, pscf->downstream_buf_size);
|
p = ngx_pnalloc(c->pool, pscf->downstream_buf_size);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
ngx_stream_proxy_finalize(s, NGX_ERROR);
|
ngx_stream_proxy_finalize(s, NGX_ERROR);
|
||||||
@ -342,6 +353,29 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s)
|
|||||||
c->write->handler = ngx_stream_proxy_downstream_handler;
|
c->write->handler = ngx_stream_proxy_downstream_handler;
|
||||||
c->read->handler = ngx_stream_proxy_downstream_handler;
|
c->read->handler = ngx_stream_proxy_downstream_handler;
|
||||||
|
|
||||||
|
if (u->proxy_protocol
|
||||||
|
#if (NGX_STREAM_SSL)
|
||||||
|
&& pscf->ssl == NULL
|
||||||
|
#endif
|
||||||
|
&& pscf->downstream_buf_size >= NGX_PROXY_PROTOCOL_MAX_HEADER
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* optimization for a typical case */
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||||
|
"stream proxy send PROXY protocol header");
|
||||||
|
|
||||||
|
p = ngx_proxy_protocol_write(c, u->downstream_buf.last,
|
||||||
|
u->downstream_buf.end);
|
||||||
|
if (p == NULL) {
|
||||||
|
ngx_stream_proxy_finalize(s, NGX_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->downstream_buf.last = p;
|
||||||
|
u->proxy_protocol = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) {
|
if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -417,10 +451,18 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
|
|||||||
ngx_stream_upstream_t *u;
|
ngx_stream_upstream_t *u;
|
||||||
ngx_stream_proxy_srv_conf_t *pscf;
|
ngx_stream_proxy_srv_conf_t *pscf;
|
||||||
|
|
||||||
pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
|
|
||||||
|
|
||||||
u = s->upstream;
|
u = s->upstream;
|
||||||
|
|
||||||
|
if (u->proxy_protocol) {
|
||||||
|
if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->proxy_protocol = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
|
||||||
|
|
||||||
pc = u->peer.connection;
|
pc = u->peer.connection;
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
@ -474,6 +516,76 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s)
|
||||||
|
{
|
||||||
|
u_char *p;
|
||||||
|
ssize_t n, size;
|
||||||
|
ngx_connection_t *c, *pc;
|
||||||
|
ngx_stream_upstream_t *u;
|
||||||
|
ngx_stream_proxy_srv_conf_t *pscf;
|
||||||
|
u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
|
||||||
|
|
||||||
|
c = s->connection;
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||||
|
"stream proxy send PROXY protocol header");
|
||||||
|
|
||||||
|
p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
|
||||||
|
if (p == NULL) {
|
||||||
|
ngx_stream_proxy_finalize(s, NGX_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = s->upstream;
|
||||||
|
|
||||||
|
pc = u->peer.connection;
|
||||||
|
|
||||||
|
size = p - buf;
|
||||||
|
|
||||||
|
n = pc->send(pc, buf, size);
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN) {
|
||||||
|
if (ngx_handle_write_event(pc->write, 0) != NGX_OK) {
|
||||||
|
ngx_stream_proxy_finalize(s, NGX_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
|
||||||
|
|
||||||
|
ngx_add_timer(pc->write, pscf->timeout);
|
||||||
|
|
||||||
|
pc->write->handler = ngx_stream_proxy_connect_handler;
|
||||||
|
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == NGX_ERROR) {
|
||||||
|
ngx_stream_proxy_finalize(s, NGX_DECLINED);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n != size) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PROXY protocol specification:
|
||||||
|
* The sender must always ensure that the header
|
||||||
|
* is sent at once, so that the transport layer
|
||||||
|
* maintains atomicity along the path to the receiver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||||
|
"could not send PROXY protocol header at once");
|
||||||
|
|
||||||
|
ngx_stream_proxy_finalize(s, NGX_DECLINED);
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
@ -1105,6 +1217,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
|
|||||||
conf->upstream_buf_size = NGX_CONF_UNSET_SIZE;
|
conf->upstream_buf_size = NGX_CONF_UNSET_SIZE;
|
||||||
conf->next_upstream_tries = NGX_CONF_UNSET_UINT;
|
conf->next_upstream_tries = NGX_CONF_UNSET_UINT;
|
||||||
conf->next_upstream = NGX_CONF_UNSET;
|
conf->next_upstream = NGX_CONF_UNSET;
|
||||||
|
conf->proxy_protocol = NGX_CONF_UNSET;
|
||||||
conf->local = NGX_CONF_UNSET_PTR;
|
conf->local = NGX_CONF_UNSET_PTR;
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
@ -1146,6 +1259,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||||||
|
|
||||||
ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1);
|
ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1);
|
||||||
|
|
||||||
|
ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0);
|
||||||
|
|
||||||
ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
|
ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
|
||||||
|
|
||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
|
@ -86,6 +86,8 @@ typedef struct {
|
|||||||
#if (NGX_STREAM_SSL)
|
#if (NGX_STREAM_SSL)
|
||||||
ngx_str_t ssl_name;
|
ngx_str_t ssl_name;
|
||||||
#endif
|
#endif
|
||||||
|
ngx_uint_t proxy_protocol;
|
||||||
|
/* unsigned proxy_protocol:1; */
|
||||||
} ngx_stream_upstream_t;
|
} ngx_stream_upstream_t;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user