[tests] Add -blocknotify functional test
[bitcoinplatinum.git] / test / functional / proxy_test.py
blob81b99d1bf4484a787d91f29db9880242ae90909e
1 #!/usr/bin/env python3
2 # Copyright (c) 2015-2016 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 bitcoind with different proxy configuration.
7 Test plan:
8 - Start bitcoind's with different proxy configurations
9 - Use addnode to initiate connections
10 - Verify that proxies are connected to, and the right connection command is given
11 - Proxy configurations to test on bitcoind side:
12 - `-proxy` (proxy everything)
13 - `-onion` (proxy just onions)
14 - `-proxyrandomize` Circuit randomization
15 - Proxy configurations to test on proxy side,
16 - support no authentication (other proxy)
17 - support no authentication + user/pass authentication (Tor)
18 - proxy on IPv6
20 - Create various proxies (as threads)
21 - Create bitcoinds that connect to them
22 - Manipulate the bitcoinds using addnode (onetry) an observe effects
24 addnode connect to IPv4
25 addnode connect to IPv6
26 addnode connect to onion
27 addnode connect to generic DNS name
28 """
30 import socket
31 import os
33 from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
34 from test_framework.test_framework import BitcoinTestFramework
35 from test_framework.util import (
36 PORT_MIN,
37 PORT_RANGE,
38 assert_equal,
40 from test_framework.netutil import test_ipv6_local
42 RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports
44 class ProxyTest(BitcoinTestFramework):
45 def set_test_params(self):
46 self.num_nodes = 4
48 def setup_nodes(self):
49 self.have_ipv6 = test_ipv6_local()
50 # Create two proxies on different ports
51 # ... one unauthenticated
52 self.conf1 = Socks5Configuration()
53 self.conf1.addr = ('127.0.0.1', RANGE_BEGIN + (os.getpid() % 1000))
54 self.conf1.unauth = True
55 self.conf1.auth = False
56 # ... one supporting authenticated and unauthenticated (Tor)
57 self.conf2 = Socks5Configuration()
58 self.conf2.addr = ('127.0.0.1', RANGE_BEGIN + 1000 + (os.getpid() % 1000))
59 self.conf2.unauth = True
60 self.conf2.auth = True
61 if self.have_ipv6:
62 # ... one on IPv6 with similar configuration
63 self.conf3 = Socks5Configuration()
64 self.conf3.af = socket.AF_INET6
65 self.conf3.addr = ('::1', RANGE_BEGIN + 2000 + (os.getpid() % 1000))
66 self.conf3.unauth = True
67 self.conf3.auth = True
68 else:
69 self.log.warning("Testing without local IPv6 support")
71 self.serv1 = Socks5Server(self.conf1)
72 self.serv1.start()
73 self.serv2 = Socks5Server(self.conf2)
74 self.serv2.start()
75 if self.have_ipv6:
76 self.serv3 = Socks5Server(self.conf3)
77 self.serv3.start()
79 # Note: proxies are not used to connect to local nodes
80 # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost
81 args = [
82 ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
83 ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
84 ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
87 if self.have_ipv6:
88 args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
89 self.add_nodes(self.num_nodes, extra_args=args)
90 self.start_nodes()
92 def node_test(self, node, proxies, auth, test_onion=True):
93 rv = []
94 # Test: outgoing IPv4 connection through node
95 node.addnode("15.61.23.23:1234", "onetry")
96 cmd = proxies[0].queue.get()
97 assert(isinstance(cmd, Socks5Command))
98 # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
99 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
100 assert_equal(cmd.addr, b"15.61.23.23")
101 assert_equal(cmd.port, 1234)
102 if not auth:
103 assert_equal(cmd.username, None)
104 assert_equal(cmd.password, None)
105 rv.append(cmd)
107 if self.have_ipv6:
108 # Test: outgoing IPv6 connection through node
109 node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry")
110 cmd = proxies[1].queue.get()
111 assert(isinstance(cmd, Socks5Command))
112 # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
113 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
114 assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534")
115 assert_equal(cmd.port, 5443)
116 if not auth:
117 assert_equal(cmd.username, None)
118 assert_equal(cmd.password, None)
119 rv.append(cmd)
121 if test_onion:
122 # Test: outgoing onion connection through node
123 node.addnode("bitcoinostk4e4re.onion:8333", "onetry")
124 cmd = proxies[2].queue.get()
125 assert(isinstance(cmd, Socks5Command))
126 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
127 assert_equal(cmd.addr, b"bitcoinostk4e4re.onion")
128 assert_equal(cmd.port, 8333)
129 if not auth:
130 assert_equal(cmd.username, None)
131 assert_equal(cmd.password, None)
132 rv.append(cmd)
134 # Test: outgoing DNS name connection through node
135 node.addnode("node.noumenon:8333", "onetry")
136 cmd = proxies[3].queue.get()
137 assert(isinstance(cmd, Socks5Command))
138 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
139 assert_equal(cmd.addr, b"node.noumenon")
140 assert_equal(cmd.port, 8333)
141 if not auth:
142 assert_equal(cmd.username, None)
143 assert_equal(cmd.password, None)
144 rv.append(cmd)
146 return rv
148 def run_test(self):
149 # basic -proxy
150 self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False)
152 # -proxy plus -onion
153 self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False)
155 # -proxy plus -onion, -proxyrandomize
156 rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True)
157 # Check that credentials as used for -proxyrandomize connections are unique
158 credentials = set((x.username,x.password) for x in rv)
159 assert_equal(len(credentials), len(rv))
161 if self.have_ipv6:
162 # proxy on IPv6 localhost
163 self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False)
165 def networks_dict(d):
166 r = {}
167 for x in d['networks']:
168 r[x['name']] = x
169 return r
171 # test RPC getnetworkinfo
172 n0 = networks_dict(self.nodes[0].getnetworkinfo())
173 for net in ['ipv4','ipv6','onion']:
174 assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr))
175 assert_equal(n0[net]['proxy_randomize_credentials'], True)
176 assert_equal(n0['onion']['reachable'], True)
178 n1 = networks_dict(self.nodes[1].getnetworkinfo())
179 for net in ['ipv4','ipv6']:
180 assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr))
181 assert_equal(n1[net]['proxy_randomize_credentials'], False)
182 assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr))
183 assert_equal(n1['onion']['proxy_randomize_credentials'], False)
184 assert_equal(n1['onion']['reachable'], True)
186 n2 = networks_dict(self.nodes[2].getnetworkinfo())
187 for net in ['ipv4','ipv6','onion']:
188 assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr))
189 assert_equal(n2[net]['proxy_randomize_credentials'], True)
190 assert_equal(n2['onion']['reachable'], True)
192 if self.have_ipv6:
193 n3 = networks_dict(self.nodes[3].getnetworkinfo())
194 for net in ['ipv4','ipv6']:
195 assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr))
196 assert_equal(n3[net]['proxy_randomize_credentials'], False)
197 assert_equal(n3['onion']['reachable'], False)
199 if __name__ == '__main__':
200 ProxyTest().main()