[PATCH] Added so_freebind and so_transparent to the listen directive

Trygve Vea trygve.vea at redpill-linpro.com
Thu Mar 27 15:34:37 UTC 2014


# HG changeset patch
# User Trygve Vea <trygve.vea at redpill-linpro.com>
# Date 1395933815 -3600
#      Thu Mar 27 16:23:35 2014 +0100
# Node ID 13e6a37c2f57443b0d5dd0abce8d9d4ab00e31e3
# Parent  2411d4b5be2ca690a5a00a1d8ad96ff69a00317f
Added so_freebind and so_transparent to the listen directive

This solves a Linux/IPv6-specific problem.

To be able to listen to an IPv6 address that is not yet available on the host,
one need to use the IP_FREEBIND and IP_TRANSPARENT socket options.

The use case in question is for a failover setup with several service-
addresses in a IPv6-only environment.

IPv4 has a sysctl available (ip_nonlocal_bind), which is not available for
IPv6 - thus making these patches necessary.

diff -r 2411d4b5be2c -r 13e6a37c2f57 src/core/ngx_connection.c
--- a/src/core/ngx_connection.c	Wed Mar 26 18:01:11 2014 +0400
+++ b/src/core/ngx_connection.c	Thu Mar 27 16:23:35 2014 +0100
@@ -305,6 +305,14 @@
 ngx_open_listening_sockets(ngx_cycle_t *cycle)
 {
     int               reuseaddr;
+#ifdef NGX_LINUX
+#ifdef IP_FREEBIND
+    int               so_freebind;
+#endif
+#ifdef IP_TRANSPARENT
+    int               so_transparent;
+#endif
+#endif
     ngx_uint_t        i, tries, failed;
     ngx_err_t         err;
     ngx_log_t        *log;
@@ -370,6 +378,37 @@
                 return NGX_ERROR;
             }
 
+#ifdef NGX_LINUX
+#ifdef IP_FREEBIND
+            if (ls[i].so_freebind) {
+                so_freebind = (ls[i].so_freebind == 1) ? 1 : 0;
+
+                if (setsockopt(s, SOL_IP, IP_FREEBIND,
+                               (const void *) &so_freebind, sizeof(int))
+                    == -1)
+                {
+                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                                  "setsockopt(IP_FREEBIND, %d) %V failed",
+                                  so_freebind, &ls[i].addr_text);
+                }
+            }
+#endif
+#ifdef IP_TRANSPARENT
+            if (ls[i].so_transparent) {
+                so_transparent = (ls[i].so_transparent == 1) ? 1 : 0;
+
+                if (setsockopt(s, SOL_IP, IP_TRANSPARENT,
+                               (const void *) &so_transparent, sizeof(int))
+                    == -1)
+                {
+                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                                  "setsockopt(IP_TRANSPARENT, %d) %V failed",
+                                  so_transparent, &ls[i].addr_text);
+                }
+            }
+#endif
+#endif
+
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
 
             if (ls[i].sockaddr->sa_family == AF_INET6) {
diff -r 2411d4b5be2c -r 13e6a37c2f57 src/core/ngx_connection.h
--- a/src/core/ngx_connection.h	Wed Mar 26 18:01:11 2014 +0400
+++ b/src/core/ngx_connection.h	Thu Mar 27 16:23:35 2014 +0100
@@ -67,6 +67,14 @@
     unsigned            ipv6only:1;
 #endif
     unsigned            keepalive:2;
+#ifdef NGX_LINUX
+#ifdef IP_FREEBIND
+    unsigned            so_freebind:1;
+#endif
+#ifdef IP_TRANSPARENT
+    unsigned            so_transparent:1;
+#endif
+#endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT)
     unsigned            deferred_accept:1;
diff -r 2411d4b5be2c -r 13e6a37c2f57 src/http/ngx_http.c
--- a/src/http/ngx_http.c	Wed Mar 26 18:01:11 2014 +0400
+++ b/src/http/ngx_http.c	Thu Mar 27 16:23:35 2014 +0100
@@ -1791,6 +1791,14 @@
     ls->sndbuf = addr->opt.sndbuf;
 
     ls->keepalive = addr->opt.so_keepalive;
+#ifdef NGX_LINUX
+#ifdef IP_FREEBIND
+    ls->so_freebind = addr->opt.so_freebind;
+#endif
+#ifdef IP_TRANSPARENT
+    ls->so_transparent = addr->opt.so_transparent;
+#endif
+#endif
 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
     ls->keepidle = addr->opt.tcp_keepidle;
     ls->keepintvl = addr->opt.tcp_keepintvl;
diff -r 2411d4b5be2c -r 13e6a37c2f57 src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c	Wed Mar 26 18:01:11 2014 +0400
+++ b/src/http/ngx_http_core_module.c	Thu Mar 27 16:23:35 2014 +0100
@@ -4283,6 +4283,30 @@
             continue;
         }
 
+        if (ngx_strcmp(value[n].data, "so_freebind") == 0) {
+#ifdef NGX_LINUX
+            lsopt.so_freebind = 1;
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the \"so_freebind\" parameter requires "
+                               "nginx to be built for Linux");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
+        if (ngx_strcmp(value[n].data, "so_transparent") == 0) {
+#ifdef NGX_LINUX
+            lsopt.so_transparent = 1;
+            continue;
+#else
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the \"so_transparent\" parameter requires "
+                               "nginx to be built for linux");
+            return NGX_CONF_ERROR;
+#endif
+        }
+
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "invalid parameter \"%V\"", &value[n]);
         return NGX_CONF_ERROR;
diff -r 2411d4b5be2c -r 13e6a37c2f57 src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h	Wed Mar 26 18:01:11 2014 +0400
+++ b/src/http/ngx_http_core_module.h	Thu Mar 27 16:23:35 2014 +0100
@@ -82,6 +82,14 @@
     unsigned                   ipv6only:1;
 #endif
     unsigned                   so_keepalive:2;
+#ifdef NGX_LINUX
+#ifdef IP_FREEBIND
+    unsigned                   so_freebind:1;
+#endif
+#ifdef IP_TRANSPARENT
+    unsigned                   so_transparent:1;
+#endif
+#endif
     unsigned                   proxy_protocol:1;
 
     int                        backlog;



More information about the nginx-devel mailing list