test: enable `feature_bind_extra` on macOS and BSD
What changed, and why it matters
This commit only expands a Bitcoin Core test so it also runs on macOS and BSD systems, not just Linux. It adds a helper that uses the lsof command to find which network addresses a test node is listening on. There is no change to the actual Bitcoin node software that users run, and no security bug is being fixed or introduced.
No security action needed. This is a routine test-coverage change. Reviewers may optionally verify the lsof parsing regex handles all expected address formats on the newly supported platforms.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies two test-only files: feature_bind_extra.py and test_framework/netutil.py. It replaces self.skip_if_platform_not_linux() with self.skip_if_platform_not_posix() and adds a macOS/BSD implementation of get_bind_addrs(pid) that shells out to lsof -nP -a -p
Changed components
test/functional/feature_bind_extra.pytest/functional/test_framework/netutil.pyInspect captured patch +27 / −9
diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py
index ad4c4b13..91f846d6 100755
--- a/test/functional/feature_bind_extra.py
+++ b/test/functional/feature_bind_extra.py
@@ -32,8 +32,7 @@ class BindExtraTest(BitcoinTestFramework):
self.num_nodes = 3
def skip_test_if_missing_module(self):
- # Due to OS-specific network stats queries, we only run on Linux.
- self.skip_if_platform_not_linux()
+ self.skip_if_platform_not_posix()
def setup_network(self):
loopback_ipv4 = addr_to_hex("127.0.0.1")
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 5504029a..c7ab756a 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -2,7 +2,7 @@
# Copyright (c) 2014-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Linux network utilities.
+"""Linux, macOS, and BSD network utilities.
Roughly based on https://web.archive.org/web/20190424172231/http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal
"""
@@ -88,12 +88,31 @@ def get_bind_addrs(pid):
'''
Get bind addresses as (host,port) tuples for process pid.
'''
- inodes = get_socket_inodes(pid)
- bind_addrs = []
- for conn in netstat('tcp') + netstat('tcp6'):
- if conn[3] == STATE_LISTEN and conn[4] in inodes:
- bind_addrs.append(conn[1])
- return bind_addrs
+ if sys.platform == 'linux':
+ inodes = get_socket_inodes(pid)
+ bind_addrs = []
+ for conn in netstat('tcp') + netstat('tcp6'):
+ if conn[3] == STATE_LISTEN and conn[4] in inodes:
+ bind_addrs.append(conn[1])
+ return bind_addrs
+ elif sys.platform.startswith(("darwin", "freebsd", "netbsd", "openbsd")):
+ import re
+ import subprocess
+ output = subprocess.check_output(["lsof",
+ *(["-Di"] if sys.platform.startswith("freebsd") else []), # Ignore device cache to avoid stderr warnings.
+ "-nP", # Keep hosts and ports numeric.
+ "-a", # Require all filters to match.
+ "-p", str(pid), # Limit results to the target pid.
+ "-iTCP", # Only inspect TCP sockets.
+ "-sTCP:LISTEN", # Only keep listening sockets.
+ "-Ftn", # Emit machine-readable type and name fields.
+ ], text=True)
+ return [
+ (addr_to_hex(("::" if sock_type == "IPv6" else "0.0.0.0") if host == "*" else host.strip("[]")), int(port))
+ for sock_type, host, port in re.findall(r"t(IPv[46])\nn(\*|\[.+?]|[^:]+):(\d+)", output)
+ ]
+ else:
+ raise NotImplementedError(f"get_bind_addrs is not supported on {sys.platform}")
# from: https://code.activestate.com/recipes/439093/
def all_interfaces():
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.