test: use IP_PORTRANGE_HIGH on FreeBSD for dynamic port allocation

On FreeBSD, the default ephemeral port range (10000-65535) overlaps
with the test framework's static port range (11000-26000), causing
intermittent "address already in use" failures when tests use dynamic
port allocation (port=0).

Add a helper function that sets the IP_PORTRANGE/IPV6_PORTRANGE socket
option to IP_PORTRANGE_HIGH before binding, which requests ports from
the high range (49152-65535) instead. This range does not overlap with
the test framework's static ports.

Constants from FreeBSD's netinet/in.h and netinet6/in6.h:
- IP_PORTRANGE = 19 (for IPv4 sockets)
- IPV6_PORTRANGE = 14 (for IPv6 sockets)
- IP_PORTRANGE_HIGH = 1

Fixes: bitcoin/bitcoin#34331

Co-Authored-By: Vasil Dimov <vd@FreeBSD.org>
Co-Authored-By: MarcoFalke <*~=\`'#}+{/-|&$^_@721217.xyz>
This commit is contained in:
authored and w0xlt committed 2026-01-20 12:08:05 -08:00
1 parent 81bf4209e9
commit 34bed0ed8c
2 files changed
+25 -1

No files matched your search

+19
View File
@@ -181,3 +181,22 @@ def format_addr_port(addr, port):
return f"[{addr}]:{port}"
else:
return f"{addr}:{port}"
def set_ephemeral_port_range(sock):
'''On FreeBSD, set socket to use the high ephemeral port range (49152-65535).
FreeBSD's default ephemeral port range (10000-65535) overlaps with the test
framework's static port range starting at TEST_RUNNER_PORT_MIN (default=11000).
Using IP_PORTRANGE_HIGH avoids this overlap when binding to port 0 for dynamic
port allocation.
'''
if sys.platform.startswith('freebsd'):
# Constants from FreeBSD's netinet/in.h and netinet6/in6.h
IP_PORTRANGE = 19
IPV6_PORTRANGE = 14
IP_PORTRANGE_HIGH = 1 # Same value for both IPv4 and IPv6
if sock.family == socket.AF_INET6:
sock.setsockopt(socket.IPPROTO_IPV6, IPV6_PORTRANGE, IP_PORTRANGE_HIGH)
else:
sock.setsockopt(socket.IPPROTO_IP, IP_PORTRANGE, IP_PORTRANGE_HIGH)