Merge 26576 via rpc_disconnectnode_subnet

This commit is contained in:
Luke Dashjr 2025-03-05 03:27:08 +00:00
commit dfea58ac00
2 changed files with 39 additions and 5 deletions

View File

@ -430,7 +430,7 @@ static RPCHelpMan disconnectnode()
"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
"\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
{
{"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"},
{"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node or subnet"},
{"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
@ -451,7 +451,20 @@ static RPCHelpMan disconnectnode()
if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
const bool only_subnet{address_arg.get_str().find('/') != std::string::npos};
if (only_subnet) {
success = false;
} else {
success = connman.DisconnectNode(address_arg.get_str());
}
if (!success) {
const CSubNet subnet = LookupSubNet(address_arg.get_str());
if (subnet.IsValid()) {
success = connman.DisconnectNode(subnet);
} else if (only_subnet) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid subnet");
}
}
} else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) {
/* handle disconnect-by-id */
NodeId nodeid = (NodeId) id_arg.getInt<int64_t>();

View File

@ -10,6 +10,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
p2p_port,
)
class DisconnectBanTest(BitcoinTestFramework):
@ -129,8 +130,12 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: fail to disconnect when calling with junk address")
assert_raises_rpc_error(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street")
self.log.info("disconnectnode: successfully disconnect node by address")
address1 = self.nodes[0].getpeerinfo()[0]['addr']
self.log.info("disconnectnode: fail to disconnect when calling with invalid subnet")
assert_raises_rpc_error(-8, "Invalid subnet", self.nodes[0].disconnectnode, address="1.2.3.0/24\0")
self.log.info("disconnectnode: successfully disconnect node by address and port")
address1 = "127.0.0.1:" + str(p2p_port(1))
assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
self.nodes[0].disconnectnode(address=address1)
self.wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
@ -140,11 +145,27 @@ class DisconnectBanTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getpeerinfo()), 2)
assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
self.log.info("disconnectnode: successfully disconnect node by address (no port)")
nodes = self.nodes[0].getpeerinfo()
assert nodes and all(node['addr'].startswith('127.0.0.') for node in nodes)
self.nodes[0].disconnectnode(address='127.0.0.1')
self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0, timeout=10)
# reconnect the nodes
self.connect_nodes(0, 1)
self.connect_nodes(1, 0)
self.log.info("disconnectnode: successfully disconnect node by node id")
id1 = self.nodes[0].getpeerinfo()[0]['id']
id1 = [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1][0]['id']
self.nodes[0].disconnectnode(nodeid=id1)
self.wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
self.connect_nodes(0, 1) # reconnect the node
self.log.info("disconnectnode: successfully disconnect node by subnet")
nodes = self.nodes[0].getpeerinfo()
assert nodes and all(node['addr'].startswith('127.0.0.') for node in nodes)
self.nodes[0].disconnectnode(address='127.0.0.1/24')
self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0, timeout=10)
if __name__ == '__main__':
DisconnectBanTest(__file__).main()