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
<https://trac.nginx.org/nginx/ticket/287>.

Signed-off-by: Miao Wang <shankerwangmiao@gmail.com>
This commit is contained in:
Miao Wang 2024-09-07 17:19:32 +08:00
parent f45c2707ea
commit 9cdc0982a5
9 changed files with 78 additions and 0 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)