You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

p2p-leaktests.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2017 The Bitcoin Core developers
  3. # Distributed under the MIT software license, see the accompanying
  4. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. """Test message sending before handshake completion.
  6. A node should never send anything other than VERSION/VERACK/REJECT until it's
  7. received a VERACK.
  8. This test connects to a node and sends it a few messages, trying to intice it
  9. into sending us something it shouldn't.
  10. Also test that nodes that send unsupported service bits to bitcoind are disconnected
  11. and don't receive a VERACK. Unsupported service bits are currently 1 << 5 and
  12. 1 << 7 (until August 1st 2018)."""
  13. from test_framework.mininode import *
  14. from test_framework.test_framework import BitcoinTestFramework
  15. from test_framework.util import *
  16. banscore = 10
  17. class CLazyNode(NodeConnCB):
  18. def __init__(self):
  19. super().__init__()
  20. self.unexpected_msg = False
  21. self.ever_connected = False
  22. def bad_message(self, message):
  23. self.unexpected_msg = True
  24. self.log.info("should not have received message: %s" % message.command)
  25. def on_open(self, conn):
  26. self.connected = True
  27. self.ever_connected = True
  28. def on_version(self, conn, message): self.bad_message(message)
  29. def on_verack(self, conn, message): self.bad_message(message)
  30. def on_reject(self, conn, message): self.bad_message(message)
  31. def on_inv(self, conn, message): self.bad_message(message)
  32. def on_addr(self, conn, message): self.bad_message(message)
  33. def on_alert(self, conn, message): self.bad_message(message)
  34. def on_getdata(self, conn, message): self.bad_message(message)
  35. def on_getblocks(self, conn, message): self.bad_message(message)
  36. def on_tx(self, conn, message): self.bad_message(message)
  37. def on_block(self, conn, message): self.bad_message(message)
  38. def on_getaddr(self, conn, message): self.bad_message(message)
  39. def on_headers(self, conn, message): self.bad_message(message)
  40. def on_getheaders(self, conn, message): self.bad_message(message)
  41. def on_ping(self, conn, message): self.bad_message(message)
  42. def on_mempool(self, conn): self.bad_message(message)
  43. def on_pong(self, conn, message): self.bad_message(message)
  44. def on_feefilter(self, conn, message): self.bad_message(message)
  45. def on_sendheaders(self, conn, message): self.bad_message(message)
  46. def on_sendcmpct(self, conn, message): self.bad_message(message)
  47. def on_cmpctblock(self, conn, message): self.bad_message(message)
  48. def on_getblocktxn(self, conn, message): self.bad_message(message)
  49. def on_blocktxn(self, conn, message): self.bad_message(message)
  50. # Node that never sends a version. We'll use this to send a bunch of messages
  51. # anyway, and eventually get disconnected.
  52. class CNodeNoVersionBan(CLazyNode):
  53. # send a bunch of veracks without sending a message. This should get us disconnected.
  54. # NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
  55. def on_open(self, conn):
  56. super().on_open(conn)
  57. for i in range(banscore):
  58. self.send_message(msg_verack())
  59. def on_reject(self, conn, message): pass
  60. # Node that never sends a version. This one just sits idle and hopes to receive
  61. # any message (it shouldn't!)
  62. class CNodeNoVersionIdle(CLazyNode):
  63. def __init__(self):
  64. super().__init__()
  65. # Node that sends a version but not a verack.
  66. class CNodeNoVerackIdle(CLazyNode):
  67. def __init__(self):
  68. self.version_received = False
  69. super().__init__()
  70. def on_reject(self, conn, message): pass
  71. def on_verack(self, conn, message): pass
  72. # When version is received, don't reply with a verack. Instead, see if the
  73. # node will give us a message that it shouldn't. This is not an exhaustive
  74. # list!
  75. def on_version(self, conn, message):
  76. self.version_received = True
  77. conn.send_message(msg_ping())
  78. conn.send_message(msg_getaddr())
  79. class P2PLeakTest(BitcoinTestFramework):
  80. def set_test_params(self):
  81. self.num_nodes = 1
  82. self.extra_args = [['-banscore='+str(banscore)]]
  83. def run_test(self):
  84. no_version_bannode = CNodeNoVersionBan()
  85. no_version_idlenode = CNodeNoVersionIdle()
  86. no_verack_idlenode = CNodeNoVerackIdle()
  87. unsupported_service_bit5_node = CLazyNode()
  88. unsupported_service_bit7_node = CLazyNode()
  89. self.nodes[0].setmocktime(1501545600) # August 1st 2017
  90. connections = []
  91. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False))
  92. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False))
  93. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode))
  94. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5))
  95. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7))
  96. no_version_bannode.add_connection(connections[0])
  97. no_version_idlenode.add_connection(connections[1])
  98. no_verack_idlenode.add_connection(connections[2])
  99. unsupported_service_bit5_node.add_connection(connections[3])
  100. unsupported_service_bit7_node.add_connection(connections[4])
  101. NetworkThread().start() # Start up network handling in another thread
  102. wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
  103. wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
  104. wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
  105. wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10, lock=mininode_lock)
  106. wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10, lock=mininode_lock)
  107. # Mine a block and make sure that it's not sent to the connected nodes
  108. self.nodes[0].generate(1)
  109. #Give the node enough time to possibly leak out a message
  110. time.sleep(5)
  111. #This node should have been banned
  112. assert not no_version_bannode.connected
  113. # These nodes should have been disconnected
  114. assert not unsupported_service_bit5_node.connected
  115. assert not unsupported_service_bit7_node.connected
  116. [conn.disconnect_node() for conn in connections]
  117. # Wait until all connections are closed
  118. wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)
  119. # Make sure no unexpected messages came in
  120. assert(no_version_bannode.unexpected_msg == False)
  121. assert(no_version_idlenode.unexpected_msg == False)
  122. assert(no_verack_idlenode.unexpected_msg == False)
  123. assert not unsupported_service_bit5_node.unexpected_msg
  124. assert not unsupported_service_bit7_node.unexpected_msg
  125. self.log.info("Service bits 5 and 7 are allowed after August 1st 2018")
  126. self.nodes[0].setmocktime(1533168000) # August 2nd 2018
  127. allowed_service_bit5_node = NodeConnCB()
  128. allowed_service_bit7_node = NodeConnCB()
  129. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5))
  130. connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7))
  131. allowed_service_bit5_node.add_connection(connections[5])
  132. allowed_service_bit7_node.add_connection(connections[6])
  133. NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it
  134. wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock)
  135. wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock)
  136. if __name__ == '__main__':
  137. P2PLeakTest().main()