]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Improve the source port selection on Linux
authorOndřej Surý <ondrej@isc.org>
Thu, 24 Jul 2025 09:24:24 +0000 (11:24 +0200)
committerOndřej Surý <ondrej@isc.org>
Fri, 20 Feb 2026 13:06:23 +0000 (14:06 +0100)
Since 2015, Linux has introduced a new socket option to overcome TCP
limitations: When an application needs to force a source IP on an active
TCP socket it has to use bind(IP, port=x).  As most applications do not
want to deal with already used ports, x is often set to 0, meaning the
kernel is in charge to find an available port.  But kernel does not know
yet if this socket is going to be a listener or be connected. This
IP_BIND_ADDRESS_NO_PORT socket option ask the kernel to ignore the 0
port provided by application in bind(IP, port=0) and only remember the
given IP address. The port will be automatically chosen at connect()
time, in a way that allows sharing a source port as long as the 4-tuples
are unique.

Enable IP_BIND_ADDRESS_NO_PORT on the outgoing TCP sockets to overcome
this TCP limitation.

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/socket.c
lib/isc/netmgr/tcp.c

index 04e2a398c1772d7744df05438cd4f07b6c941e58..9ea93e089f6168316ff74169ab3845ef3ac0ef7f 100644 (file)
@@ -1386,6 +1386,12 @@ isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family);
  * Use minimum MTU on IPv6 sockets
  */
 
+isc_result_t
+isc__nm_tcp_bind_no_port(uv_tcp_t *handle);
+/*%<
+ * Set IP_BIND_ADDRESS_NO_PORT on the socket (Linux only).
+ */
+
 void
 isc__nm_set_network_buffers(uv_handle_t *handle);
 /*%>
index 4b71e9dbfd188d18f66f07bcbb38e93fcf0b833b..d75beb97b6a2bdffa2aaa48914b21d4a5751d5ee 100644 (file)
@@ -369,3 +369,20 @@ isc__nm_socket_min_mtu(uv_os_sock_t fd, sa_family_t sa_family) {
 
        return ISC_R_SUCCESS;
 }
+
+isc_result_t
+isc__nm_tcp_bind_no_port(uv_tcp_t *handle ISC_ATTR_UNUSED) {
+#ifdef IP_BIND_ADDRESS_NO_PORT
+       uv_os_sock_t fd = -1;
+
+       int r = uv_fileno((const uv_handle_t *)handle, (uv_os_fd_t *)&fd);
+       if (r < 0) {
+               return ISC_R_FAILURE;
+       }
+
+       if (setsockopt_on(fd, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT) == -1) {
+               return ISC_R_FAILURE;
+       }
+#endif
+       return ISC_R_SUCCESS;
+}
index 84e57693bbbb0d3bd07a041ed08806da4879e536..7dd7184cfeaf40d0cae26bacce7299bc97b12b4b 100644 (file)
@@ -141,6 +141,8 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
        }
        isc__nm_incstats(sock, STATID_OPEN);
 
+       isc__nm_tcp_bind_no_port(&sock->uv_handle.tcp);
+
        if (req->local.length != 0) {
                r = uv_tcp_bind(&sock->uv_handle.tcp, &req->local.type.sa, 0);
                if (r != 0) {