﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc	uname	nginx_version
2187	nginx -t disrupts streamed udp traffic	bartebor@…		"`nginx -t` creates sockets with socket option `SO_REUSEADDR`. This, at least in linux, allows UDP sockets to bind successfully. This makes some of the streamed traffic lost regardless of the state of `SO_REUSEPORT` being recommended setting in `listen` directive. This effect is more pronounced with large configurations, where testing may take a few seconds.

I think `SO_REUSEADDR` should be disabled (at least for UDP sockets) in the same way `SO_REUSEPORT` is in testing mode.

I tested this with nginx 1.18.x, but relevant code is still there in more recent versions.

Sample config (saved to `$(pwd)/etc/nginx/nginx.conf`):
{{{
# load_module ""/usr/lib/nginx/modules/ngx_stream_module.so""; # if not compiled in
daemon off;
worker_processes 1;
pid /tmp/nginx.pid;

error_log /dev/stderr error;


events {
        worker_connections 1024;
}

stream {
        upstream uudp {
                server 127.0.0.1:4444 down;
        }

        server {
                listen 127.0.0.1:3333 udp reuseport;

                proxy_pass uudp;
        }
}
}}}
Now, we start nginx and then test the config:
{{{
$ /usr/sbin/nginx  -p  $(pwd) -c $(pwd)/etc/nginx/nginx.conf &
[1] 1659171
$ strace -esocket,setsockopt,bind /usr/sbin/nginx  -p  $(pwd) -c $(pwd)/etc/nginx/nginx.conf -t
nginx: the configuration file /tmp/etc/nginx/nginx.conf syntax is ok
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(4, {sa_family=AF_INET, sin_port=htons(3333), sin_addr=inet_addr(""127.0.0.1"")}, 16) = 0
nginx: configuration file /tmp/etc/nginx/nginx.conf test is successful
+++ exited with 0 +++
}}}

As strace shows there is `SO_REUSEADDR` set, `SO_REUSEPORT` is not set and `bind` is successful.

With simple patch disabling `SO_REUSEADDR` in test mode:
{{{
diff -ur nginx.orig/src/core/ngx_connection.c nginx.new/src/core/ngx_connection.c
--- nginx.orig/src/core/ngx_connection.c        2021-05-18 16:41:55.627284469 +0200
+++ nginx.new/src/core/ngx_connection.c 2021-05-18 16:44:11.321172445 +0200
@@ -495,7 +495,7 @@
                 return NGX_ERROR;
             }
 
-            if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+            if (!ngx_test_config && setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                            (const void *) &reuseaddr, sizeof(int))
                 == -1)
             {
}}}
 the strace output is:
{{{
$ strace -esocket,setsockopt,bind /usr/sbin/nginx  -p  $(pwd) -c $(pwd)/etc/nginx/nginx.conf -t
nginx: the configuration file /tmp/etc/nginx/nginx.conf syntax is ok
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(4, {sa_family=AF_INET, sin_port=htons(3333), sin_addr=inet_addr(""127.0.0.1"")}, 16) = -1 EADDRINUSE (Address already in use)
nginx: configuration file /tmp/etc/nginx/nginx.conf test is successful
+++ exited with 0 +++
}}}
"	defect	closed	major		nginx-core	1.18.x	fixed			Linux host 5.4.69-1.el7.x86_64 #1 SMP Wed Oct 7 08:43:39 CEST 2020 x86_64 x86_64 x86_64 GNU/Linux	not relevant
