test: extend FreeBSD ephemeral port range fix to P2P listeners
What changed, and why it matters
This is a test-only change for Bitcoin Core's internal Python test framework. It fixes a port-conflict problem that could occur when running automated tests on FreeBSD, by making sure randomly chosen network ports for test P2P listeners come from a range that does not clash with the test framework's hard-coded ports. It does not affect the Bitcoin Core software that users run, does not change consensus or networking behavior, and has no security relevance for live Bitcoin nodes.
No security action required. Treat as a normal test-framework reliability improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit modifies test/functional/test_framework/p2p.py so that when NetworkThread.create_listen_server() is asked to bind to port 0 (dynamic allocation), it manually creates a socket, calls set_ephemeral_port_range() to request FreeBSD’s high ephemeral range (49152-65535), then binds/listens and passes that socket to asyncio’s create_server(). Previously this was only done for the SOCKS5 server. The change prevents dynamic test ports from overlapping the test framework’s static port assignments on FreeBSD, reducing spurious test failures. It is purely a testing infrastructure reliability fix.
Changed components
test/functional/test_framework/p2p.pyNetworkThread.create_listen_server()Inspect captured patch +21 / −2
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index 986eaf1e..8102da7a 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -22,9 +22,11 @@ P2PTxInvStore: A p2p interface class that inherits from P2PDataStore, and keeps
import asyncio
from collections import defaultdict
+import ipaddress
from io import BytesIO
import logging
import platform
+import socket
import struct
import sys
import threading
@@ -76,6 +78,9 @@ from test_framework.messages import (
MAGIC_BYTES,
sha256,
)
+from test_framework.netutil import (
+ set_ephemeral_port_range,
+)
from test_framework.util import (
assert_not_equal,
MAX_NODES,
@@ -793,8 +798,22 @@ class NetworkThread(threading.Thread):
# connections, we can accomplish this by providing different
# `proto` functions
- listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
- port = listener.sockets[0].getsockname()[1]
+ if port == 0:
+ # Manually create the socket in order to set the range to be
+ # used for the port before the bind() call.
+ if ipaddress.ip_address(addr).version == 4:
+ address_family = socket.AF_INET
+ else:
+ address_family = socket.AF_INET6
+ s = socket.socket(address_family)
+ set_ephemeral_port_range(s)
+ s.bind((addr, 0))
+ s.listen()
+ listener = await cls.network_event_loop.create_server(peer_protocol, sock=s)
+ port = listener.sockets[0].getsockname()[1]
+ else:
+ listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
+
logger.debug("Listening server on %s:%d should be started" % (addr, port))
cls.listeners[(addr, port)] = listener
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.