[tests] Avoid passing around member variables in test_framework
[bitcoinplatinum.git] / test / functional / proxy_test.py
blobadbbda278daca644f6086361e2da8551cca66749
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
45 class ProxyTest(BitcoinTestFramework):
46 def __init__(self):
47 super().__init__()
48 self.num_nodes = 4
49 self.setup_clean_chain = False
51 def setup_nodes(self):
52 self.have_ipv6 = test_ipv6_local()
53 # Create two proxies on different ports
54 # ... one unauthenticated
55 self.conf1 = Socks5Configuration()
56 self.conf1.addr = ('127.0.0.1', RANGE_BEGIN + (os.getpid() % 1000))
57 self.conf1.unauth = True
58 self.conf1.auth = False
59 # ... one supporting authenticated and unauthenticated (Tor)
60 self.conf2 = Socks5Configuration()
61 self.conf2.addr = ('127.0.0.1', RANGE_BEGIN + 1000 + (os.getpid() % 1000))
62 self.conf2.unauth = True
63 self.conf2.auth = True
64 if self.have_ipv6:
65 # ... one on IPv6 with similar configuration
66 self.conf3 = Socks5Configuration()
67 self.conf3.af = socket.AF_INET6
68 self.conf3.addr = ('::1', RANGE_BEGIN + 2000 + (os.getpid() % 1000))
69 self.conf3.unauth = True
70 self.conf3.auth = True
71 else:
72 self.log.warning("Testing without local IPv6 support")
74 self.serv1 = Socks5Server(self.conf1)
75 self.serv1.start()
76 self.serv2 = Socks5Server(self.conf2)
77 self.serv2.start()
78 if self.have_ipv6:
79 self.serv3 = Socks5Server(self.conf3)
80 self.serv3.start()
82 # Note: proxies are not used to connect to local nodes
83 # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost
84 args = [
85 ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
86 ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
87 ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
90 if self.have_ipv6:
91 args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
92 self.add_nodes(self.num_nodes, extra_args=args)
93 self.start_nodes()
95 def node_test(self, node, proxies, auth, test_onion=True):
96 rv = []
97 # Test: outgoing IPv4 connection through node
98 node.addnode("15.61.23.23:1234", "onetry")
99 cmd = proxies[0].queue.get()
100 assert(isinstance(cmd, Socks5Command))
101 # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
102 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
103 assert_equal(cmd.addr, b"15.61.23.23")
104 assert_equal(cmd.port, 1234)
105 if not auth:
106 assert_equal(cmd.username, None)
107 assert_equal(cmd.password, None)
108 rv.append(cmd)
110 if self.have_ipv6:
111 # Test: outgoing IPv6 connection through node
112 node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry")
113 cmd = proxies[1].queue.get()
114 assert(isinstance(cmd, Socks5Command))
115 # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
116 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
117 assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534")
118 assert_equal(cmd.port, 5443)
119 if not auth:
120 assert_equal(cmd.username, None)
121 assert_equal(cmd.password, None)
122 rv.append(cmd)
124 if test_onion:
125 # Test: outgoing onion connection through node
126 node.addnode("bitcoinostk4e4re.onion:8333", "onetry")
127 cmd = proxies[2].queue.get()
128 assert(isinstance(cmd, Socks5Command))
129 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
130 assert_equal(cmd.addr, b"bitcoinostk4e4re.onion")
131 assert_equal(cmd.port, 8333)
132 if not auth:
133 assert_equal(cmd.username, None)
134 assert_equal(cmd.password, None)
135 rv.append(cmd)
137 # Test: outgoing DNS name connection through node
138 node.addnode("node.noumenon:8333", "onetry")
139 cmd = proxies[3].queue.get()
140 assert(isinstance(cmd, Socks5Command))
141 assert_equal(cmd.atyp, AddressType.DOMAINNAME)
142 assert_equal(cmd.addr, b"node.noumenon")
143 assert_equal(cmd.port, 8333)
144 if not auth:
145 assert_equal(cmd.username, None)
146 assert_equal(cmd.password, None)
147 rv.append(cmd)
149 return rv
151 def run_test(self):
152 # basic -proxy
153 self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False)
155 # -proxy plus -onion
156 self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False)
158 # -proxy plus -onion, -proxyrandomize
159 rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True)
160 # Check that credentials as used for -proxyrandomize connections are unique
161 credentials = set((x.username,x.password) for x in rv)
162 assert_equal(len(credentials), len(rv))
164 if self.have_ipv6:
165 # proxy on IPv6 localhost
166 self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False)
168 def networks_dict(d):
169 r = {}
170 for x in d['networks']:
171 r[x['name']] = x
172 return r
174 # test RPC getnetworkinfo
175 n0 = networks_dict(self.nodes[0].getnetworkinfo())
176 for net in ['ipv4','ipv6','onion']:
177 assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr))
178 assert_equal(n0[net]['proxy_randomize_credentials'], True)
179 assert_equal(n0['onion']['reachable'], True)
181 n1 = networks_dict(self.nodes[1].getnetworkinfo())
182 for net in ['ipv4','ipv6']:
183 assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr))
184 assert_equal(n1[net]['proxy_randomize_credentials'], False)
185 assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr))
186 assert_equal(n1['onion']['proxy_randomize_credentials'], False)
187 assert_equal(n1['onion']['reachable'], True)
189 n2 = networks_dict(self.nodes[2].getnetworkinfo())
190 for net in ['ipv4','ipv6','onion']:
191 assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr))
192 assert_equal(n2[net]['proxy_randomize_credentials'], True)
193 assert_equal(n2['onion']['reachable'], True)
195 if self.have_ipv6:
196 n3 = networks_dict(self.nodes[3].getnetworkinfo())
197 for net in ['ipv4','ipv6']:
198 assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr))
199 assert_equal(n3[net]['proxy_randomize_credentials'], False)
200 assert_equal(n3['onion']['reachable'], False)
202 if __name__ == '__main__':
203 ProxyTest().main()