summaryrefslogtreecommitdiffhomepage
path: root/src/event/ngx_event_connect.c
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2015-12-18 19:05:27 +0300
committerRoman Arutyunyan <arut@nginx.com>2015-12-18 19:05:27 +0300
commitbe79f5cb16eeb452e2a9e343a89f89b3b47bc5a2 (patch)
tree00ab618ce2f89cd97f91982cf822f74cc8e16754 /src/event/ngx_event_connect.c
parent77ec993fd7300423aab8f6c798082b9421f51a24 (diff)
downloadnginx-be79f5cb16eeb452e2a9e343a89f89b3b47bc5a2.tar.gz
nginx-be79f5cb16eeb452e2a9e343a89f89b3b47bc5a2.tar.bz2
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;
Diffstat (limited to 'src/event/ngx_event_connect.c')
-rw-r--r--src/event/ngx_event_connect.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
index 8aca86252..5de991e07 100644
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -11,6 +11,12 @@
#include <ngx_event_connect.h>
+#if (NGX_HAVE_TRANSPARENT_PROXY)
+static ngx_int_t ngx_event_connect_set_transparent(ngx_peer_connection_t *pc,
+ ngx_socket_t s);
+#endif
+
+
ngx_int_t
ngx_event_connect_peer(ngx_peer_connection_t *pc)
{
@@ -72,6 +78,15 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
}
if (pc->local) {
+
+#if (NGX_HAVE_TRANSPARENT_PROXY)
+ if (pc->transparent) {
+ if (ngx_event_connect_set_transparent(pc, s) != NGX_OK) {
+ goto failed;
+ }
+ }
+#endif
+
if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) {
ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno,
"bind(%V) failed", &pc->local->name);
@@ -249,6 +264,94 @@ failed:
}
+#if (NGX_HAVE_TRANSPARENT_PROXY)
+
+static ngx_int_t
+ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
+{
+ int value;
+
+ value = 1;
+
+#if defined(SO_BINDANY)
+
+ if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
+ (const void *) &value, sizeof(int)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(SO_BINDANY) failed");
+ return NGX_ERROR;
+ }
+
+#else
+
+ switch (pc->local->sockaddr->sa_family) {
+
+ case AF_INET:
+
+#if defined(IP_TRANSPARENT)
+
+ if (setsockopt(s, IPPROTO_IP, IP_TRANSPARENT,
+ (const void *) &value, sizeof(int)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(IP_TRANSPARENT) failed");
+ return NGX_ERROR;
+ }
+
+#elif defined(IP_BINDANY)
+
+ if (setsockopt(s, IPPROTO_IP, IP_BINDANY,
+ (const void *) &value, sizeof(int)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(IP_BINDANY) failed");
+ return NGX_ERROR;
+ }
+
+#endif
+
+ break;
+
+#if (NGX_HAVE_INET6)
+
+ case AF_INET6:
+
+#if defined(IPV6_TRANSPARENT)
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_TRANSPARENT,
+ (const void *) &value, sizeof(int)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(IPV6_TRANSPARENT) failed");
+ return NGX_ERROR;
+ }
+
+#elif defined(IPV6_BINDANY)
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_BINDANY,
+ (const void *) &value, sizeof(int)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(IPV6_BINDANY) failed");
+ return NGX_ERROR;
+ }
+
+#endif
+ break;
+
+#endif /* NGX_HAVE_INET6 */
+
+ }
+
+#endif /* SO_BINDANY */
+
+ return NGX_OK;
+}
+
+#endif
+
+
ngx_int_t
ngx_event_get_peer(ngx_peer_connection_t *pc, void *data)
{