]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't enable SO_REUSEADDR on outgoing UDP sockets
authorOndřej Surý <ondrej@isc.org>
Mon, 30 Sep 2024 16:01:47 +0000 (18:01 +0200)
committerOndřej Surý <ondrej@isc.org>
Wed, 2 Oct 2024 12:15:53 +0000 (12:15 +0000)
Currently, the outgoing UDP sockets have enabled
SO_REUSEADDR (SO_REUSEPORT on BSDs) which allows multiple UDP sockets to
bind to the same address+port.  There's one caveat though - only a
single (the last one) socket is going to receive all the incoming
traffic.  This in turn could lead to incoming DNS message matching to
invalid dns_dispatch and getting dropped.

Disable setting the SO_REUSEADDR on the outgoing UDP sockets.  This
needs to be done explicitly because `uv_udp_open()` silently enables the
option on the socket.

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/socket.c
lib/isc/netmgr/tcp.c
lib/isc/netmgr/udp.c
tests/isc/doh_test.c

index d45734ecc77b2299ae4f6d82eaaf808056417226..c7f721b2a0610cf06260ace810838cd876e4962f 100644 (file)
@@ -1321,7 +1321,7 @@ isc__nm_closesocket(uv_os_sock_t sock);
  */
 
 isc_result_t
-isc__nm_socket_reuse(uv_os_sock_t fd);
+isc__nm_socket_reuse(uv_os_sock_t fd, int val);
 /*%<
  * Set the SO_REUSEADDR or SO_REUSEPORT (or equivalent) socket option on the fd
  */
index 7440c0b855736a5f440a7bdfe1c3d0f55da4d660..8f02dc848dad5fea15630b6296adba16c852dea8 100644 (file)
@@ -159,7 +159,7 @@ isc__nm_closesocket(uv_os_sock_t sock) {
 }
 
 isc_result_t
-isc__nm_socket_reuse(uv_os_sock_t fd) {
+isc__nm_socket_reuse(uv_os_sock_t fd, int val) {
        /*
         * Generally, the SO_REUSEADDR socket option allows reuse of
         * local addresses.
@@ -173,12 +173,12 @@ isc__nm_socket_reuse(uv_os_sock_t fd) {
         */
 
 #if defined(SO_REUSEPORT) && !defined(__linux__)
-       if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEPORT) == -1) {
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)) == -1) {
                return (ISC_R_FAILURE);
        }
        return (ISC_R_SUCCESS);
 #elif defined(SO_REUSEADDR)
-       if (setsockopt_on(fd, SOL_SOCKET, SO_REUSEADDR) == -1) {
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == -1) {
                return (ISC_R_FAILURE);
        }
        return (ISC_R_SUCCESS);
index f43b1118b035d05af0b89b9a6f390232f9c679c4..1916b799985144405d3dda2cf12b597d89e9844a 100644 (file)
@@ -289,7 +289,7 @@ isc__nm_tcp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
 
        /* FIXME: set mss */
 
-       result = isc__nm_socket_reuse(sock);
+       result = isc__nm_socket_reuse(sock, 1);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
        if (mgr->load_balance_sockets) {
index 82f99a61c8d4443343fcf2022fdc6ae467c8f2fa..4da1db8519ad0281f45fea64261fb5ce2eafb626 100644 (file)
@@ -78,7 +78,7 @@ isc__nm_udp_lb_socket(isc_nm_t *mgr, sa_family_t sa_family) {
        (void)isc__nm_socket_disable_pmtud(sock, sa_family);
        (void)isc__nm_socket_v6only(sock, sa_family);
 
-       result = isc__nm_socket_reuse(sock);
+       result = isc__nm_socket_reuse(sock, 1);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 
        if (mgr->load_balance_sockets) {
@@ -752,9 +752,10 @@ fail:
 
 static isc_result_t
 udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
-       int uv_bind_flags = UV_UDP_REUSEADDR;
+       int uv_bind_flags = 0;
        int r;
        isc__networker_t *worker = sock->worker;
+       isc_result_t result;
 
        r = uv_udp_init(&worker->loop->loop, &sock->uv_handle.udp);
        UV_RUNTIME_CHECK(uv_udp_init, r);
@@ -771,6 +772,12 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
        }
        isc__nm_incstats(sock, STATID_OPEN);
 
+       /*
+        * uv_udp_open() enables REUSE_ADDR, we need to disable it again.
+        */
+       result = isc__nm_socket_reuse(sock->fd, 0);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
        if (sock->iface.type.sa.sa_family == AF_INET6) {
                uv_bind_flags |= UV_UDP_IPV6ONLY;
        }
@@ -846,9 +853,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
        sock->client = true;
 
        sock->fd = fd;
-       result = isc__nm_socket_reuse(sock->fd);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS ||
-                     result == ISC_R_NOTIMPLEMENTED);
 
        (void)isc__nm_socket_disable_pmtud(sock->fd, sa_family);
 
index 072816cf242edcbb7511fd0355d307a0aadc1124..c8240281f99316df03eca5c2c72a1cb50b514892 100644 (file)
@@ -247,7 +247,7 @@ setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
                return (r);
        }
 
-       result = isc__nm_socket_reuse(fd);
+       result = isc__nm_socket_reuse(fd, 1);
        if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
                fprintf(stderr,
                        "setup_ephemeral_port: isc__nm_socket_reuse(): %s",