From 9cdc0982a567a73943797444c4dca3484430f150 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Sat, 7 Sep 2024 17:19:32 +0800 Subject: [PATCH] IP_TRANSPARENT support for listening sockets This patch adds support for IP_TRANSPARENT support for listening sockets in the http module and stream module. Adding `transparent` to ths options of a listen directive, IP_TRANSPARENT will be enabled on that listening socket, allowing it to accept traffic redirected using TPROXY. When this is enabled, the original destination IP address and port before the redirection can be fetched from the variables $server_addr and $server_port. The original version of this patch was proposed by Stijn Tintel in . Signed-off-by: Miao Wang --- src/core/ngx_connection.c | 16 ++++++++++++++++ src/core/ngx_connection.h | 5 +++++ src/event/ngx_event_accept.c | 13 +++++++++++++ src/http/ngx_http.c | 5 +++++ src/http/ngx_http_core_module.c | 11 +++++++++++ src/http/ngx_http_core_module.h | 5 +++++ src/stream/ngx_stream.c | 4 ++++ src/stream/ngx_stream.h | 5 +++++ src/stream/ngx_stream_core_module.c | 14 ++++++++++++++ 9 files changed, 78 insertions(+) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 75809d9ad..912a03aae 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -563,6 +563,22 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) } #endif +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + if (ls[i].transparent) { + int transparent = 1; + + if (setsockopt(s, SOL_IP, IP_TRANSPARENT, + (const void *) &transparent, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(IP_TRANSPARENT) for %V failed, " + "ignored", + &ls[i].addr_text); + } + } +#endif + #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ls[i].sockaddr->sa_family == AF_INET6) { diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 84dd80442..de0748953 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -78,6 +78,11 @@ struct ngx_listening_s { unsigned deferred_accept:1; unsigned delete_deferred:1; unsigned add_deferred:1; +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + unsigned transparent:1; +#else + unsigned :1; +#endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) char *accept_filter; #endif diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 27038799d..2119524fc 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -215,8 +215,21 @@ ngx_event_accept(ngx_event_t *ev) c->socklen = socklen; c->listening = ls; +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + if(ls->transparent) { + c->local_sockaddr = NULL; + c->local_socklen = 0; + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + ngx_close_accepted_connection(c); + return; + } + }else{ +#endif c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + } +#endif #if (NGX_HAVE_UNIX_DOMAIN) if (c->sockaddr->sa_family == AF_UNIX) { diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index d835f896e..b912434b1 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1850,6 +1850,11 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->sndbuf = addr->opt.sndbuf; ls->keepalive = addr->opt.so_keepalive; + +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + ls->transparent = addr->opt.transparent; +#endif + #if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr->opt.tcp_keepidle; ls->keepintvl = addr->opt.tcp_keepintvl; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 033a3bf64..9175ecb13 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4126,6 +4126,17 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strcmp(value[n].data, "transparent") == 0) { +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + lsopt.transparent = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "transparent mode is not supported " + "on this platform, ignored"); +#endif + continue; + } + if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) { #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) if (ngx_strcmp(&value[n].data[10], "n") == 0) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 765e7ff60..424ee48c1 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -83,6 +83,11 @@ typedef struct { unsigned reuseport:1; unsigned so_keepalive:2; unsigned proxy_protocol:1; +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + unsigned transparent:1; +#else + unsigned :1; +#endif int backlog; int rcvbuf; diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index b6eeb23af..512fbfa89 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -1045,6 +1045,10 @@ ngx_stream_add_listening(ngx_conf_t *cf, ngx_stream_conf_addr_t *addr) ls->reuseport = addr->opt.reuseport; #endif +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + ls->transparent = addr->opt.transparent; +#endif + ls->wildcard = addr->opt.wildcard; return ls; diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index dc05dc5ba..ff0547198 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -57,6 +57,11 @@ typedef struct { unsigned reuseport:1; unsigned so_keepalive:2; unsigned proxy_protocol:1; +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + unsigned transparent:1; +#else + unsigned :1; +#endif int backlog; int rcvbuf; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 40951c291..bb2e5c8e6 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -930,6 +930,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) lsopt.ipv6only = 1; #endif +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + lsopt.transparent = 0; +#endif + backlog = 0; for (i = 2; i < cf->args->nelts; i++) { @@ -1033,6 +1037,16 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } + if (ngx_strcmp(value[i].data, "transparent") == 0) { +#if (NGX_HAVE_TRANSPARENT_PROXY && defined IP_TRANSPARENT) + lsopt.transparent = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "transparent mode is not supported " + "on this platform, ignored"); +#endif + continue; + } if (ngx_strncmp(value[i].data, "accept_filter=", 14) == 0) { #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)