Mercurial > hg > nginx
diff src/stream/ngx_stream_proxy_module.c @ 6530:1d0e03db9f8e
Upstream: the "transparent" parameter of proxy_bind and friends.
This parameter lets binding the proxy connection to a non-local address.
Upstream will see the connection as coming from that address.
When used with $remote_addr, upstream will accept the connection from real
client address.
Example:
proxy_bind $remote_addr transparent;
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 18 Dec 2015 19:05:27 +0300 |
parents | cb8177ca0990 |
children | 04d8d1f85649 |
line wrap: on
line diff
--- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -12,6 +12,9 @@ typedef struct { ngx_addr_t *addr; +#if (NGX_HAVE_TRANSPARENT_PROXY) + ngx_uint_t transparent; /* unsigned transparent:1; */ +#endif } ngx_stream_upstream_local_t; @@ -120,7 +123,7 @@ static ngx_command_t ngx_stream_proxy_c NULL }, { ngx_string("proxy_bind"), - NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE12, ngx_stream_proxy_bind, NGX_STREAM_SRV_CONF_OFFSET, 0, @@ -443,16 +446,63 @@ static ngx_int_t ngx_stream_proxy_set_local(ngx_stream_session_t *s, ngx_stream_upstream_t *u, ngx_stream_upstream_local_t *local) { + ngx_addr_t *addr; + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + if (local == NULL) { u->peer.local = NULL; return NGX_OK; } +#if (NGX_HAVE_TRANSPARENT_PROXY) + u->peer.transparent = local->transparent; +#endif + if (local->addr) { u->peer.local = local->addr; return NGX_OK; } + /* $remote_addr */ + + c = s->connection; + + addr = ngx_palloc(c->pool, sizeof(ngx_addr_t)); + if (addr == NULL) { + return NGX_ERROR; + } + + addr->socklen = c->socklen; + + addr->sockaddr = ngx_palloc(c->pool, addr->socklen); + if (addr->sockaddr == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(addr->sockaddr, c->sockaddr, c->socklen); + + switch (addr->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_port = 0; + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + sin6->sin6_port = 0; + break; +#endif + } + + addr->name = c->addr_text; + u->peer.local = addr; + return NGX_OK; } @@ -1676,7 +1726,7 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng value = cf->args->elts; - if (ngx_strcmp(value[1].data, "off") == 0) { + if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) { pscf->local = NULL; return NGX_CONF_OK; } @@ -1688,25 +1738,44 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng pscf->local = local; - local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); - if (local->addr == NULL) { - return NGX_CONF_ERROR; + if (ngx_strcmp(value[1].data, "$remote_addr") != 0) { + local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (local->addr == NULL) { + return NGX_CONF_ERROR; + } + + rc = ngx_parse_addr(cf->pool, local->addr, value[1].data, value[1].len); + + switch (rc) { + case NGX_OK: + local->addr->name = value[1]; + break; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + /* fall through */ + + default: + return NGX_CONF_ERROR; + } } - rc = ngx_parse_addr(cf->pool, local->addr, value[1].data, value[1].len); - - switch (rc) { - case NGX_OK: - local->addr->name = value[1]; - break; + if (cf->args->nelts > 2) { + if (ngx_strcmp(value[2].data, "transparent") == 0) { +#if (NGX_HAVE_TRANSPARENT_PROXY) + local->transparent = 1; - case NGX_DECLINED: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid address \"%V\"", &value[1]); - /* fall through */ - - default: - return NGX_CONF_ERROR; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "transparent proxying is not supported " + "on this platform, ignored"); +#endif + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } } return NGX_CONF_OK;