diff options
Diffstat (limited to 'test/functional/p2p_leak.py')
-rwxr-xr-x | test/functional/p2p_leak.py | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 06049db54c..157af68203 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2019 The Bitcoin Core developers +# Copyright (c) 2017-2020 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test message sending before handshake completion. -A node should never send anything other than VERSION/VERACK/REJECT until it's +A node should never send anything other than VERSION/VERACK until it's received a VERACK. This test connects to a node and sends it a few messages, trying to entice it @@ -12,13 +12,23 @@ into sending us something it shouldn't.""" import time -from test_framework.messages import msg_getaddr, msg_ping, msg_verack +from test_framework.messages import ( + msg_getaddr, + msg_ping, + msg_verack, + msg_version, +) from test_framework.mininode import mininode_lock, P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import wait_until +from test_framework.util import ( + assert_equal, + assert_greater_than_or_equal, + wait_until, +) banscore = 10 + class CLazyNode(P2PInterface): def __init__(self): super().__init__() @@ -27,14 +37,13 @@ class CLazyNode(P2PInterface): def bad_message(self, message): self.unexpected_msg = True - self.log.info("should not have received message: %s" % message.command) + self.log.info("should not have received message: %s" % message.msgtype) def on_open(self): self.ever_connected = True def on_version(self, message): self.bad_message(message) def on_verack(self, message): self.bad_message(message) - def on_reject(self, message): self.bad_message(message) def on_inv(self, message): self.bad_message(message) def on_addr(self, message): self.bad_message(message) def on_getdata(self, message): self.bad_message(message) @@ -64,8 +73,6 @@ class CNodeNoVersionBan(CLazyNode): for i in range(banscore): self.send_message(msg_verack()) - def on_reject(self, message): pass - # Node that never sends a version. This one just sits idle and hopes to receive # any message (it shouldn't!) class CNodeNoVersionIdle(CLazyNode): @@ -78,7 +85,6 @@ class CNodeNoVerackIdle(CLazyNode): self.version_received = False super().__init__() - def on_reject(self, message): pass def on_verack(self, message): pass # When version is received, don't reply with a verack. Instead, see if the # node will give us a message that it shouldn't. This is not an exhaustive @@ -88,6 +94,15 @@ class CNodeNoVerackIdle(CLazyNode): self.send_message(msg_ping()) self.send_message(msg_getaddr()) + +class P2PVersionStore(P2PInterface): + version_received = None + + def on_version(self, msg): + super().on_version(msg) + self.version_received = msg + + class P2PLeakTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -96,7 +111,11 @@ class P2PLeakTest(BitcoinTestFramework): def run_test(self): no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) - no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle()) + no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle(), wait_for_verack=False) + + # Wait until we got the verack in response to the version. Though, don't wait for the other node to receive the + # verack, since we never sent one + no_verack_idlenode.wait_for_verack() wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock) wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock) @@ -121,6 +140,26 @@ class P2PLeakTest(BitcoinTestFramework): assert no_version_idlenode.unexpected_msg == False assert no_verack_idlenode.unexpected_msg == False + self.log.info('Check that the version message does not leak the local address of the node') + p2p_version_store = self.nodes[0].add_p2p_connection(P2PVersionStore()) + ver = p2p_version_store.version_received + # Check that received time is within one hour of now + assert_greater_than_or_equal(ver.nTime, time.time() - 3600) + assert_greater_than_or_equal(time.time() + 3600, ver.nTime) + assert_equal(ver.addrFrom.port, 0) + assert_equal(ver.addrFrom.ip, '0.0.0.0') + assert_equal(ver.nStartingHeight, 201) + assert_equal(ver.nRelay, 1) + + self.log.info('Check that old nodes are disconnected') + p2p_old_node = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) + old_version_msg = msg_version() + old_version_msg.nVersion = 31799 + wait_until(lambda: p2p_old_node.is_connected) + with self.nodes[0].assert_debug_log(['peer=4 using obsolete version 31799; disconnecting']): + p2p_old_node.send_message(old_version_msg) + p2p_old_node.wait_for_disconnect() + if __name__ == '__main__': P2PLeakTest().main() |