From 7ad2d6e986aa69845abeceb2f07390e0ec13ee66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 30 Sep 2024 18:01:47 +0200 Subject: [PATCH] Don't enable SO_REUSEADDR on outgoing UDP sockets 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. (cherry picked from commit eec30c33c2336f3f139ec54e29367916e2c22fd7) --- lib/isc/netmgr/netmgr-int.h | 2 +- lib/isc/netmgr/netmgr.c | 6 +++--- lib/isc/netmgr/tcp.c | 2 +- lib/isc/netmgr/tcpdns.c | 2 +- lib/isc/netmgr/tlsdns.c | 2 +- lib/isc/netmgr/udp.c | 14 ++++++++------ tests/isc/doh_test.c | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index b4f1dd37fe..a99153a8f2 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -1967,7 +1967,7 @@ isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family); */ 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 */ diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 3034390a34..f412d08509 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -3278,7 +3278,7 @@ isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family) { } 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. @@ -3295,12 +3295,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); diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c index 9524a72cf0..b277eda9b4 100644 --- a/lib/isc/netmgr/tcp.c +++ b/lib/isc/netmgr/tcp.c @@ -387,7 +387,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) { diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index 39575a9fa5..0e00265c36 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -350,7 +350,7 @@ isc__nm_tcpdns_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) { diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index afe7bcdfab..6054d8d9ae 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -460,7 +460,7 @@ isc__nm_tlsdns_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) { diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 7e8d6d077f..835d8d8f58 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -97,7 +97,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) { @@ -893,7 +893,7 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req, static isc_result_t udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { isc__networker_t *worker = NULL; - int uv_bind_flags = UV_UDP_REUSEADDR; + int uv_bind_flags = 0; isc_result_t result = ISC_R_UNSET; int r; @@ -924,6 +924,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; } @@ -1055,10 +1061,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, return; } - result = isc__nm_socket_reuse(sock->fd); - RUNTIME_CHECK(result == ISC_R_SUCCESS || - result == ISC_R_NOTIMPLEMENTED); - result = isc__nm_socket_reuse_lb(sock->fd); RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_NOTIMPLEMENTED); diff --git a/tests/isc/doh_test.c b/tests/isc/doh_test.c index 090fb8f318..dc658621d6 100644 --- a/tests/isc/doh_test.c +++ b/tests/isc/doh_test.c @@ -218,7 +218,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",