|
5 | 5 |
|
6 | 6 | # Test for -rpcbind, as well as -rpcallowip and -rpcconnect |
7 | 7 |
|
8 | | -# TODO extend this test from the test framework (like all other tests) |
9 | | - |
10 | 8 | import tempfile |
11 | 9 | import traceback |
12 | 10 |
|
| 11 | +from test_framework.test_framework import BitcoinTestFramework |
13 | 12 | from test_framework.util import * |
14 | 13 | from test_framework.netutil import * |
15 | 14 |
|
16 | | -def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected): |
17 | | - ''' |
18 | | - Start a node with requested rpcallowip and rpcbind parameters, |
19 | | - then try to connect, and check if the set of bound addresses |
20 | | - matches the expected set. |
21 | | - ''' |
22 | | - expected = [(addr_to_hex(addr), port) for (addr, port) in expected] |
23 | | - base_args = ['-disablewallet', '-nolisten'] |
24 | | - if allow_ips: |
25 | | - base_args += ['-rpcallowip=' + x for x in allow_ips] |
26 | | - binds = ['-rpcbind='+addr for addr in addresses] |
27 | | - nodes = start_nodes(self.num_nodes, tmpdir, [base_args + binds], connect_to) |
28 | | - try: |
29 | | - pid = bitcoind_processes[0].pid |
30 | | - assert_equal(set(get_bind_addrs(pid)), set(expected)) |
31 | | - finally: |
32 | | - stop_nodes(nodes) |
33 | | - wait_bitcoinds() |
34 | | - |
35 | | -def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport): |
36 | | - ''' |
37 | | - Start a node with rpcwallow IP, and request getinfo |
38 | | - at a non-localhost IP. |
39 | | - ''' |
40 | | - base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] |
41 | | - nodes = start_nodes(self.num_nodes, tmpdir, [base_args]) |
42 | | - try: |
43 | | - # connect to node through non-loopback interface |
44 | | - url = "http://rt:rt@%s:%d" % (rpchost, rpcport,) |
45 | | - node = get_rpc_proxy(url, 1) |
46 | | - node.getinfo() |
47 | | - finally: |
48 | | - node = None # make sure connection will be garbage collected and closed |
49 | | - stop_nodes(nodes) |
50 | | - wait_bitcoinds() |
51 | | - |
52 | | - |
53 | | -def run_test(tmpdir): |
54 | | - assert(sys.platform.startswith('linux')) # due to OS-specific network stats queries, this test works only on Linux |
55 | | - # find the first non-loopback interface for testing |
56 | | - non_loopback_ip = None |
57 | | - for name,ip in all_interfaces(): |
58 | | - if ip != '127.0.0.1': |
59 | | - non_loopback_ip = ip |
60 | | - break |
61 | | - if non_loopback_ip is None: |
62 | | - assert(not 'This test requires at least one non-loopback IPv4 interface') |
63 | | - print("Using interface %s for testing" % non_loopback_ip) |
| 15 | +class RPCBindTest(BitcoinTestFramework): |
64 | 16 |
|
65 | | - defaultport = rpc_port(0) |
| 17 | + def __init__(self): |
| 18 | + super().__init__() |
| 19 | + self.setup_clean_chain = True |
| 20 | + self.num_nodes = 1 |
66 | 21 |
|
67 | | - # check default without rpcallowip (IPv4 and IPv6 localhost) |
68 | | - run_bind_test(tmpdir, None, '127.0.0.1', [], |
69 | | - [('127.0.0.1', defaultport), ('::1', defaultport)]) |
70 | | - # check default with rpcallowip (IPv6 any) |
71 | | - run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', [], |
72 | | - [('::0', defaultport)]) |
73 | | - # check only IPv4 localhost (explicit) |
74 | | - run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1'], |
75 | | - [('127.0.0.1', defaultport)]) |
76 | | - # check only IPv4 localhost (explicit) with alternative port |
77 | | - run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'], |
78 | | - [('127.0.0.1', 32171)]) |
79 | | - # check only IPv4 localhost (explicit) with multiple alternative ports on same host |
80 | | - run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'], |
81 | | - [('127.0.0.1', 32171), ('127.0.0.1', 32172)]) |
82 | | - # check only IPv6 localhost (explicit) |
83 | | - run_bind_test(tmpdir, ['[::1]'], '[::1]', ['[::1]'], |
84 | | - [('::1', defaultport)]) |
85 | | - # check both IPv4 and IPv6 localhost (explicit) |
86 | | - run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'], |
87 | | - [('127.0.0.1', defaultport), ('::1', defaultport)]) |
88 | | - # check only non-loopback interface |
89 | | - run_bind_test(tmpdir, [non_loopback_ip], non_loopback_ip, [non_loopback_ip], |
90 | | - [(non_loopback_ip, defaultport)]) |
91 | | - |
92 | | - # Check that with invalid rpcallowip, we are denied |
93 | | - run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip, defaultport) |
94 | | - try: |
95 | | - run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip, defaultport) |
96 | | - assert(not 'Connection not denied by rpcallowip as expected') |
97 | | - except ValueError: |
| 22 | + def setup_network(self): |
98 | 23 | pass |
99 | 24 |
|
100 | | -def main(): |
101 | | - import optparse |
102 | | - |
103 | | - parser = optparse.OptionParser(usage="%prog [options]") |
104 | | - parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", |
105 | | - help="Leave bitcoinds and test.* datadir on exit or error") |
106 | | - parser.add_option("--srcdir", dest="srcdir", default="../../src", |
107 | | - help="Source directory containing bitcoind/bitcoin-cli (default: %default%)") |
108 | | - parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), |
109 | | - help="Root directory for datadirs") |
110 | | - (options, args) = parser.parse_args() |
111 | | - |
112 | | - os.environ['PATH'] = options.srcdir+":"+os.environ['PATH'] |
113 | | - |
114 | | - check_json_precision() |
115 | | - |
116 | | - success = False |
117 | | - nodes = [] |
118 | | - try: |
119 | | - print("Initializing test directory "+options.tmpdir) |
120 | | - if not os.path.isdir(options.tmpdir): |
121 | | - os.makedirs(options.tmpdir) |
122 | | - initialize_chain(options.tmpdir) |
123 | | - |
124 | | - run_test(options.tmpdir) |
125 | | - |
126 | | - success = True |
127 | | - |
128 | | - except AssertionError as e: |
129 | | - print("Assertion failed: "+e.message) |
130 | | - except Exception as e: |
131 | | - print("Unexpected exception caught during testing: "+str(e)) |
132 | | - traceback.print_tb(sys.exc_info()[2]) |
133 | | - |
134 | | - if not options.nocleanup: |
135 | | - print("Cleaning up") |
136 | | - wait_bitcoinds() |
137 | | - shutil.rmtree(options.tmpdir) |
| 25 | + def setup_nodes(self): |
| 26 | + pass |
138 | 27 |
|
139 | | - if success: |
140 | | - print("Tests successful") |
141 | | - sys.exit(0) |
142 | | - else: |
143 | | - print("Failed") |
144 | | - sys.exit(1) |
| 28 | + def run_bind_test(self, allow_ips, connect_to, addresses, expected): |
| 29 | + ''' |
| 30 | + Start a node with requested rpcallowip and rpcbind parameters, |
| 31 | + then try to connect, and check if the set of bound addresses |
| 32 | + matches the expected set. |
| 33 | + ''' |
| 34 | + expected = [(addr_to_hex(addr), port) for (addr, port) in expected] |
| 35 | + base_args = ['-disablewallet', '-nolisten'] |
| 36 | + if allow_ips: |
| 37 | + base_args += ['-rpcallowip=' + x for x in allow_ips] |
| 38 | + binds = ['-rpcbind='+addr for addr in addresses] |
| 39 | + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to) |
| 40 | + try: |
| 41 | + pid = bitcoind_processes[0].pid |
| 42 | + assert_equal(set(get_bind_addrs(pid)), set(expected)) |
| 43 | + finally: |
| 44 | + stop_nodes(self.nodes) |
| 45 | + wait_bitcoinds() |
| 46 | + |
| 47 | + def run_allowip_test(self, allow_ips, rpchost, rpcport): |
| 48 | + ''' |
| 49 | + Start a node with rpcwallow IP, and request getinfo |
| 50 | + at a non-localhost IP. |
| 51 | + ''' |
| 52 | + base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] |
| 53 | + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) |
| 54 | + try: |
| 55 | + # connect to node through non-loopback interface |
| 56 | + node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0) |
| 57 | + node.getinfo() |
| 58 | + finally: |
| 59 | + node = None # make sure connection will be garbage collected and closed |
| 60 | + stop_nodes(self.nodes) |
| 61 | + wait_bitcoinds() |
| 62 | + |
| 63 | + def run_test(self): |
| 64 | + # due to OS-specific network stats queries, this test works only on Linux |
| 65 | + assert(sys.platform.startswith('linux')) |
| 66 | + # find the first non-loopback interface for testing |
| 67 | + non_loopback_ip = None |
| 68 | + for name,ip in all_interfaces(): |
| 69 | + if ip != '127.0.0.1': |
| 70 | + non_loopback_ip = ip |
| 71 | + break |
| 72 | + if non_loopback_ip is None: |
| 73 | + assert(not 'This test requires at least one non-loopback IPv4 interface') |
| 74 | + print("Using interface %s for testing" % non_loopback_ip) |
| 75 | + |
| 76 | + defaultport = rpc_port(0) |
| 77 | + |
| 78 | + # check default without rpcallowip (IPv4 and IPv6 localhost) |
| 79 | + self.run_bind_test(None, '127.0.0.1', [], |
| 80 | + [('127.0.0.1', defaultport), ('::1', defaultport)]) |
| 81 | + # check default with rpcallowip (IPv6 any) |
| 82 | + self.run_bind_test(['127.0.0.1'], '127.0.0.1', [], |
| 83 | + [('::0', defaultport)]) |
| 84 | + # check only IPv4 localhost (explicit) |
| 85 | + self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'], |
| 86 | + [('127.0.0.1', defaultport)]) |
| 87 | + # check only IPv4 localhost (explicit) with alternative port |
| 88 | + self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'], |
| 89 | + [('127.0.0.1', 32171)]) |
| 90 | + # check only IPv4 localhost (explicit) with multiple alternative ports on same host |
| 91 | + self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'], |
| 92 | + [('127.0.0.1', 32171), ('127.0.0.1', 32172)]) |
| 93 | + # check only IPv6 localhost (explicit) |
| 94 | + self.run_bind_test(['[::1]'], '[::1]', ['[::1]'], |
| 95 | + [('::1', defaultport)]) |
| 96 | + # check both IPv4 and IPv6 localhost (explicit) |
| 97 | + self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'], |
| 98 | + [('127.0.0.1', defaultport), ('::1', defaultport)]) |
| 99 | + # check only non-loopback interface |
| 100 | + self.run_bind_test([non_loopback_ip], non_loopback_ip, [non_loopback_ip], |
| 101 | + [(non_loopback_ip, defaultport)]) |
| 102 | + |
| 103 | + # Check that with invalid rpcallowip, we are denied |
| 104 | + self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport) |
| 105 | + try: |
| 106 | + self.run_allowip_test(['1.1.1.1'], non_loopback_ip, defaultport) |
| 107 | + assert(not 'Connection not denied by rpcallowip as expected') |
| 108 | + except JSONRPCException: |
| 109 | + pass |
145 | 110 |
|
146 | 111 | if __name__ == '__main__': |
147 | | - main() |
| 112 | + RPCBindTest ().main () |
0 commit comments