/ test / functional / feature_proxy.py
feature_proxy.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2015-present 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.
  6  
  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      - `-cjdnsreachable`
 16  - Proxy configurations to test on proxy side,
 17      - support no authentication (other proxy)
 18      - support no authentication + user/pass authentication (Tor)
 19      - proxy on IPv6
 20      - proxy over unix domain sockets
 21  
 22  - Create various proxies (as threads)
 23  - Create nodes that connect to them
 24  - Manipulate the peer connections using addnode (onetry) and observe effects
 25  - Test the getpeerinfo `network` field for the peer
 26  
 27  addnode connect to IPv4
 28  addnode connect to IPv6
 29  addnode connect to onion
 30  addnode connect to generic DNS name
 31  addnode connect to a CJDNS address
 32  
 33  - Test getnetworkinfo for each node
 34  
 35  - Test passing invalid -proxy
 36  - Test passing invalid -onion
 37  - Test passing invalid -i2psam
 38  - Test passing -onlynet=onion without -proxy or -onion
 39  - Test passing -onlynet=onion with -onion=0 and with -noonion
 40  - Test passing unknown -onlynet
 41  """
 42  
 43  import os
 44  import socket
 45  import tempfile
 46  
 47  from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
 48  from test_framework.test_framework import BitcoinTestFramework
 49  from test_framework.util import assert_equal
 50  from test_framework.netutil import test_ipv6_local, test_unix_socket
 51  
 52  # Networks returned by RPC getpeerinfo.
 53  NET_UNROUTABLE = "not_publicly_routable"
 54  NET_IPV4 = "ipv4"
 55  NET_IPV6 = "ipv6"
 56  NET_ONION = "onion"
 57  NET_I2P = "i2p"
 58  NET_CJDNS = "cjdns"
 59  
 60  # Networks returned by RPC getnetworkinfo, defined in src/rpc/net.cpp::GetNetworksInfo()
 61  NETWORKS = frozenset({NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS})
 62  
 63  # Use the shortest temp path possible since UNIX sockets may have as little as 92-char limit
 64  socket_path = tempfile.NamedTemporaryFile().name
 65  
 66  class ProxyTest(BitcoinTestFramework):
 67      def set_test_params(self):
 68          self.num_nodes = 7
 69          self.setup_clean_chain = True
 70  
 71      def setup_nodes(self):
 72          self.have_ipv6 = test_ipv6_local()
 73          self.have_unix_sockets = test_unix_socket()
 74          # Create two proxies on different ports.
 75          # Use port=0 to let the OS assign available ports, avoiding
 76          # "address already in use" errors from concurrent tests.
 77          # ... one unauthenticated
 78          self.conf1 = Socks5Configuration()
 79          self.conf1.addr = ('127.0.0.1', 0)
 80          self.conf1.unauth = True
 81          self.conf1.auth = False
 82          # ... one supporting authenticated and unauthenticated (Tor)
 83          self.conf2 = Socks5Configuration()
 84          self.conf2.addr = ('127.0.0.1', 0)
 85          self.conf2.unauth = True
 86          self.conf2.auth = True
 87          if self.have_ipv6:
 88              # ... one on IPv6 with similar configuration
 89              self.conf3 = Socks5Configuration()
 90              self.conf3.af = socket.AF_INET6
 91              self.conf3.addr = ('::1', 0)
 92              self.conf3.unauth = True
 93              self.conf3.auth = True
 94          else:
 95              self.log.warning("Testing without local IPv6 support")
 96  
 97          if self.have_unix_sockets:
 98              self.conf4 = Socks5Configuration()
 99              self.conf4.af = socket.AF_UNIX
100              self.conf4.addr = socket_path
101              self.conf4.unauth = True
102              self.conf4.auth = True
103          else:
104              self.log.warning("Testing without local unix domain sockets support")
105  
106          self.serv1 = Socks5Server(self.conf1)
107          self.serv1.start()
108          self.serv2 = Socks5Server(self.conf2)
109          self.serv2.start()
110          if self.have_ipv6:
111              self.serv3 = Socks5Server(self.conf3)
112              self.serv3.start()
113          if self.have_unix_sockets:
114              self.serv4 = Socks5Server(self.conf4)
115              self.serv4.start()
116  
117          # We will not try to connect to this.
118          self.i2p_sam = ('127.0.0.1', 7656)
119  
120          # Note: proxies are not used to connect to local nodes. This is because the proxy to
121          # use is based on CService.GetNetwork(), which returns NET_UNROUTABLE for localhost.
122          args = [
123              ['-listen', f'-proxy={self.conf1.addr[0]}:{self.conf1.addr[1]}','-proxyrandomize=1'],
124              ['-listen', f'-proxy={self.conf1.addr[0]}:{self.conf1.addr[1]}',f'-onion={self.conf2.addr[0]}:{self.conf2.addr[1]}',
125                  f'-i2psam={self.i2p_sam[0]}:{self.i2p_sam[1]}', '-i2pacceptincoming=0', '-proxyrandomize=0'],
126              ['-listen', f'-proxy={self.conf2.addr[0]}:{self.conf2.addr[1]}','-proxyrandomize=1'],
127              [],
128              ['-listen', f'-proxy={self.conf1.addr[0]}:{self.conf1.addr[1]}','-proxyrandomize=1',
129                  '-cjdnsreachable'],
130              [],
131              []
132          ]
133          if self.have_ipv6:
134              args[3] = ['-listen', f'-proxy=[{self.conf3.addr[0]}]:{self.conf3.addr[1]}','-proxyrandomize=0', '-noonion']
135          if self.have_unix_sockets:
136              args[5] = ['-listen', f'-proxy=unix:{socket_path}']
137              args[6] = ['-listen', f'-onion=unix:{socket_path}']
138          self.add_nodes(self.num_nodes, extra_args=args)
139          self.start_nodes()
140  
141      def network_test(self, node, addr, network):
142          for peer in node.getpeerinfo():
143              if peer["addr"] == addr:
144                  assert_equal(peer["network"], network)
145  
146      def node_test(self, node, *, proxies, auth, test_onion, test_cjdns):
147          rv = []
148          addr = "15.61.23.23:1234"
149          self.log.debug(f"Test: outgoing IPv4 connection through node {node.index} for address {addr}")
150          # v2transport=False is used to avoid reconnections with v1 being scheduled. These could interfere with later checks.
151          node.addnode(addr, "onetry", v2transport=False)
152          cmd = proxies[0].queue.get()
153          assert isinstance(cmd, Socks5Command)
154          # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
155          assert_equal(cmd.atyp, AddressType.DOMAINNAME)
156          assert_equal(cmd.addr, b"15.61.23.23")
157          assert_equal(cmd.port, 1234)
158          if not auth:
159              assert_equal(cmd.username, None)
160              assert_equal(cmd.password, None)
161          rv.append(cmd)
162          self.network_test(node, addr, network=NET_IPV4)
163  
164          if self.have_ipv6:
165              addr = "[1233:3432:2434:2343:3234:2345:6546:4534]:5443"
166              self.log.debug(f"Test: outgoing IPv6 connection through node {node.index} for address {addr}")
167              node.addnode(addr, "onetry", v2transport=False)
168              cmd = proxies[1].queue.get()
169              assert isinstance(cmd, Socks5Command)
170              # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
171              assert_equal(cmd.atyp, AddressType.DOMAINNAME)
172              assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534")
173              assert_equal(cmd.port, 5443)
174              if not auth:
175                  assert_equal(cmd.username, None)
176                  assert_equal(cmd.password, None)
177              rv.append(cmd)
178              self.network_test(node, addr, network=NET_IPV6)
179  
180          if test_onion:
181              addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333"
182              self.log.debug(f"Test: outgoing onion connection through node {node.index} for address {addr}")
183              node.addnode(addr, "onetry", v2transport=False)
184              cmd = proxies[2].queue.get()
185              assert isinstance(cmd, Socks5Command)
186              assert_equal(cmd.atyp, AddressType.DOMAINNAME)
187              assert_equal(cmd.addr, b"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")
188              assert_equal(cmd.port, 8333)
189              if not auth:
190                  assert_equal(cmd.username, None)
191                  assert_equal(cmd.password, None)
192              rv.append(cmd)
193              self.network_test(node, addr, network=NET_ONION)
194  
195          if test_cjdns:
196              addr = "[fc00:1:2:3:4:5:6:7]:8888"
197              self.log.debug(f"Test: outgoing CJDNS connection through node {node.index} for address {addr}")
198              node.addnode(addr, "onetry", v2transport=False)
199              cmd = proxies[1].queue.get()
200              assert isinstance(cmd, Socks5Command)
201              assert_equal(cmd.atyp, AddressType.DOMAINNAME)
202              assert_equal(cmd.addr, b"fc00:1:2:3:4:5:6:7")
203              assert_equal(cmd.port, 8888)
204              if not auth:
205                  assert_equal(cmd.username, None)
206                  assert_equal(cmd.password, None)
207              rv.append(cmd)
208              self.network_test(node, addr, network=NET_CJDNS)
209  
210          addr = "node.noumenon:8333"
211          self.log.debug(f"Test: outgoing DNS name connection through node {node.index} for address {addr}")
212          node.addnode(addr, "onetry", v2transport=False)
213          cmd = proxies[3].queue.get()
214          assert isinstance(cmd, Socks5Command)
215          assert_equal(cmd.atyp, AddressType.DOMAINNAME)
216          assert_equal(cmd.addr, b"node.noumenon")
217          assert_equal(cmd.port, 8333)
218          if not auth:
219              assert_equal(cmd.username, None)
220              assert_equal(cmd.password, None)
221          rv.append(cmd)
222          self.network_test(node, addr, network=NET_UNROUTABLE)
223  
224          return rv
225  
226      def run_test(self):
227          # basic -proxy
228          self.node_test(self.nodes[0],
229              proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
230              auth=False, test_onion=True, test_cjdns=False)
231  
232          # -proxy plus -onion
233          self.node_test(self.nodes[1],
234              proxies=[self.serv1, self.serv1, self.serv2, self.serv1],
235              auth=False, test_onion=True, test_cjdns=False)
236  
237          # -proxy plus -onion, -proxyrandomize
238          rv = self.node_test(self.nodes[2],
239              proxies=[self.serv2, self.serv2, self.serv2, self.serv2],
240              auth=True, test_onion=True, test_cjdns=False)
241          # Check that credentials as used for -proxyrandomize connections are unique
242          credentials = set((x.username,x.password) for x in rv)
243          assert_equal(len(credentials), len(rv))
244  
245          if self.have_ipv6:
246              # proxy on IPv6 localhost
247              self.node_test(self.nodes[3],
248                  proxies=[self.serv3, self.serv3, self.serv3, self.serv3],
249                  auth=False, test_onion=False, test_cjdns=False)
250  
251          # -proxy=unauth -proxyrandomize=1 -cjdnsreachable
252          self.node_test(self.nodes[4],
253              proxies=[self.serv1, self.serv1, self.serv1, self.serv1],
254              auth=False, test_onion=True, test_cjdns=True)
255  
256          if self.have_unix_sockets:
257              self.node_test(self.nodes[5],
258                  proxies=[self.serv4, self.serv4, self.serv4, self.serv4],
259                  auth=True, test_onion=True, test_cjdns=False)
260  
261  
262          def networks_dict(d):
263              r = {}
264              for x in d['networks']:
265                  r[x['name']] = x
266              return r
267  
268          self.log.info("Test RPC getnetworkinfo")
269          nodes_network_info = []
270  
271          self.log.debug("Test that setting -proxy disables local address discovery, i.e. -discover=0")
272          for node in self.nodes:
273              network_info = node.getnetworkinfo()
274              assert_equal(network_info["localaddresses"], [])
275              nodes_network_info.append(network_info)
276  
277          n0 = networks_dict(nodes_network_info[0])
278          assert_equal(NETWORKS, n0.keys())
279          for net in NETWORKS:
280              if net == NET_I2P:
281                  expected_proxy = ''
282                  expected_randomize = False
283              else:
284                  expected_proxy = '%s:%i' % (self.conf1.addr)
285                  expected_randomize = True
286              assert_equal(n0[net]['proxy'], expected_proxy)
287              assert_equal(n0[net]['proxy_randomize_credentials'], expected_randomize)
288          assert_equal(n0['onion']['reachable'], True)
289          assert_equal(n0['i2p']['reachable'], False)
290          assert_equal(n0['cjdns']['reachable'], False)
291  
292          n1 = networks_dict(nodes_network_info[1])
293          assert_equal(NETWORKS, n1.keys())
294          for net in ['ipv4', 'ipv6']:
295              assert_equal(n1[net]['proxy'], f'{self.conf1.addr[0]}:{self.conf1.addr[1]}')
296              assert_equal(n1[net]['proxy_randomize_credentials'], False)
297          assert_equal(n1['onion']['proxy'], f'{self.conf2.addr[0]}:{self.conf2.addr[1]}')
298          assert_equal(n1['onion']['proxy_randomize_credentials'], False)
299          assert_equal(n1['onion']['reachable'], True)
300          assert_equal(n1['i2p']['proxy'], f'{self.i2p_sam[0]}:{self.i2p_sam[1]}')
301          assert_equal(n1['i2p']['proxy_randomize_credentials'], False)
302          assert_equal(n1['i2p']['reachable'], True)
303  
304          n2 = networks_dict(nodes_network_info[2])
305          assert_equal(NETWORKS, n2.keys())
306          proxy = f'{self.conf2.addr[0]}:{self.conf2.addr[1]}'
307          for net in NETWORKS:
308              if net == NET_I2P:
309                  expected_proxy = ''
310                  expected_randomize = False
311              else:
312                  expected_proxy = proxy
313                  expected_randomize = True
314              assert_equal(n2[net]['proxy'], expected_proxy)
315              assert_equal(n2[net]['proxy_randomize_credentials'], expected_randomize)
316          assert_equal(n2['onion']['reachable'], True)
317          assert_equal(n2['i2p']['reachable'], False)
318          assert_equal(n2['cjdns']['reachable'], False)
319  
320          if self.have_ipv6:
321              n3 = networks_dict(nodes_network_info[3])
322              assert_equal(NETWORKS, n3.keys())
323              proxy = f'[{self.conf3.addr[0]}]:{self.conf3.addr[1]}'
324              for net in NETWORKS:
325                  expected_proxy = '' if net == NET_I2P or net == NET_ONION else proxy
326                  assert_equal(n3[net]['proxy'], expected_proxy)
327                  assert_equal(n3[net]['proxy_randomize_credentials'], False)
328              assert_equal(n3['onion']['reachable'], False)
329              assert_equal(n3['i2p']['reachable'], False)
330              assert_equal(n3['cjdns']['reachable'], False)
331  
332          n4 = networks_dict(nodes_network_info[4])
333          assert_equal(NETWORKS, n4.keys())
334          for net in NETWORKS:
335              if net == NET_I2P:
336                  expected_proxy = ''
337                  expected_randomize = False
338              else:
339                  expected_proxy = '%s:%i' % (self.conf1.addr)
340                  expected_randomize = True
341              assert_equal(n4[net]['proxy'], expected_proxy)
342              assert_equal(n4[net]['proxy_randomize_credentials'], expected_randomize)
343          assert_equal(n4['onion']['reachable'], True)
344          assert_equal(n4['i2p']['reachable'], False)
345          assert_equal(n4['cjdns']['reachable'], True)
346  
347          if self.have_unix_sockets:
348              n5 = networks_dict(nodes_network_info[5])
349              assert_equal(NETWORKS, n5.keys())
350              for net in NETWORKS:
351                  if net == NET_I2P:
352                      expected_proxy = ''
353                      expected_randomize = False
354                  else:
355                      expected_proxy = 'unix:' + self.conf4.addr # no port number
356                      expected_randomize = True
357                  assert_equal(n5[net]['proxy'], expected_proxy)
358                  assert_equal(n5[net]['proxy_randomize_credentials'], expected_randomize)
359              assert_equal(n5['onion']['reachable'], True)
360              assert_equal(n5['i2p']['reachable'], False)
361              assert_equal(n5['cjdns']['reachable'], False)
362  
363              n6 = networks_dict(nodes_network_info[6])
364              assert_equal(NETWORKS, n6.keys())
365              for net in NETWORKS:
366                  if net != NET_ONION:
367                      expected_proxy = ''
368                      expected_randomize = False
369                  else:
370                      expected_proxy = 'unix:' + self.conf4.addr # no port number
371                      expected_randomize = True
372                  assert_equal(n6[net]['proxy'], expected_proxy)
373                  assert_equal(n6[net]['proxy_randomize_credentials'], expected_randomize)
374              assert_equal(n6['onion']['reachable'], True)
375              assert_equal(n6['i2p']['reachable'], False)
376              assert_equal(n6['cjdns']['reachable'], False)
377  
378          self.stop_node(1)
379  
380          self.log.info("Test passing invalid -proxy hostname raises expected init error")
381          self.nodes[1].extra_args = ["-proxy=abc..abc:23456"]
382          msg = "Error: Invalid -proxy address or hostname: 'abc..abc:23456'"
383          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
384  
385          self.log.info("Test passing invalid -proxy port raises expected init error")
386          self.nodes[1].extra_args = ["-proxy=192.0.0.1:def"]
387          msg = "Error: Invalid port specified in -proxy: '192.0.0.1:def'"
388          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
389  
390          self.log.info("Test passing invalid -onion hostname raises expected init error")
391          self.nodes[1].extra_args = ["-onion=xyz..xyz:23456"]
392          msg = "Error: Invalid -onion address or hostname: 'xyz..xyz:23456'"
393          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
394  
395          self.log.info("Test passing invalid -onion port raises expected init error")
396          self.nodes[1].extra_args = ["-onion=192.0.0.1:def"]
397          msg = "Error: Invalid port specified in -onion: '192.0.0.1:def'"
398          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
399  
400          self.log.info("Test passing invalid -i2psam hostname raises expected init error")
401          self.nodes[1].extra_args = ["-i2psam=def..def:23456"]
402          msg = "Error: Invalid -i2psam address or hostname: 'def..def:23456'"
403          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
404  
405          self.log.info("Test passing invalid -i2psam port raises expected init error")
406          self.nodes[1].extra_args = ["-i2psam=192.0.0.1:def"]
407          msg = "Error: Invalid port specified in -i2psam: '192.0.0.1:def'"
408          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
409  
410          self.log.info("Test passing invalid -onlynet=i2p without -i2psam raises expected init error")
411          self.nodes[1].extra_args = ["-onlynet=i2p"]
412          msg = "Error: Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided"
413          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
414  
415          self.log.info("Test passing invalid -onlynet=cjdns without -cjdnsreachable raises expected init error")
416          self.nodes[1].extra_args = ["-onlynet=cjdns"]
417          msg = "Error: Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided"
418          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
419  
420          self.log.info("Test passing -onlynet=onion with -onion=0/-noonion raises expected init error")
421          msg = (
422              "Error: Outbound connections restricted to Tor (-onlynet=onion) but "
423              "the proxy for reaching the Tor network is explicitly forbidden: -onion=0"
424          )
425          for arg in ["-onion=0", "-noonion"]:
426              self.nodes[1].extra_args = ["-onlynet=onion", arg]
427              self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
428  
429          self.log.info("Test passing -onlynet=onion without -proxy, -onion or -listenonion raises expected init error")
430          self.nodes[1].extra_args = ["-onlynet=onion", "-listenonion=0"]
431          msg = (
432              "Error: Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
433              "reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given"
434          )
435          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
436  
437          self.log.info("Test passing -onlynet=onion without -proxy or -onion but with -listenonion=1 is ok")
438          self.start_node(1, extra_args=["-onlynet=onion", "-listenonion=1"])
439          self.stop_node(1)
440  
441          self.log.info("Test passing unknown network to -onlynet raises expected init error")
442          self.nodes[1].extra_args = ["-onlynet=abc"]
443          msg = "Error: Unknown network specified in -onlynet: 'abc'"
444          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
445  
446          self.log.info("Test passing trailing '=' raises expected init error")
447          self.nodes[1].extra_args = ["-proxy=127.0.0.1:9050="]
448          msg = "Error: Invalid -proxy address or hostname, ends with '=': '127.0.0.1:9050='"
449          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
450  
451          self.log.info("Test passing unrecognized network raises expected init error")
452          self.nodes[1].extra_args = ["-proxy=127.0.0.1:9050=foo"]
453          msg = "Error: Unrecognized network in -proxy='127.0.0.1:9050=foo': 'foo'"
454          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
455  
456          self.log.info("Test passing proxy only for IPv6")
457          self.start_node(1, extra_args=["-proxy=127.6.6.6:6666=ipv6"])
458          nets = networks_dict(self.nodes[1].getnetworkinfo())
459          assert_equal(nets["ipv4"]["proxy"], "")
460          assert_equal(nets["ipv6"]["proxy"], "127.6.6.6:6666")
461          self.stop_node(1)
462  
463          self.log.info("Test passing separate proxy for IPv4 and IPv6")
464          self.start_node(1, extra_args=["-proxy=127.4.4.4:4444=ipv4", "-proxy=127.6.6.6:6666=ipv6"])
465          nets = networks_dict(self.nodes[1].getnetworkinfo())
466          assert_equal(nets["ipv4"]["proxy"], "127.4.4.4:4444")
467          assert_equal(nets["ipv6"]["proxy"], "127.6.6.6:6666")
468          self.stop_node(1)
469  
470          self.log.info("Test overriding the Onion proxy")
471          self.start_node(1, extra_args=["-proxy=127.1.1.1:1111", "-proxy=127.2.2.2:2222=onion"])
472          nets = networks_dict(self.nodes[1].getnetworkinfo())
473          assert_equal(nets["ipv4"]["proxy"], "127.1.1.1:1111")
474          assert_equal(nets["ipv6"]["proxy"], "127.1.1.1:1111")
475          assert_equal(nets["onion"]["proxy"], "127.2.2.2:2222")
476          self.stop_node(1)
477  
478          self.log.info("Test removing CJDNS proxy")
479          self.start_node(1, extra_args=["-proxy=127.1.1.1:1111", "-proxy=0=cjdns"])
480          nets = networks_dict(self.nodes[1].getnetworkinfo())
481          assert_equal(nets["ipv4"]["proxy"], "127.1.1.1:1111")
482          assert_equal(nets["ipv6"]["proxy"], "127.1.1.1:1111")
483          assert_equal(nets["onion"]["proxy"], "127.1.1.1:1111")
484          assert_equal(nets["cjdns"]["proxy"], "")
485          self.stop_node(1)
486  
487          self.log.info("Test passing too-long unix path to -proxy raises init error")
488          self.nodes[1].extra_args = [f"-proxy=unix:{'x' * 1000}"]
489          if self.have_unix_sockets:
490              msg = f"Error: Invalid -proxy address or hostname: 'unix:{'x' * 1000}'"
491          else:
492              # If unix sockets are not supported, the file path is incorrectly interpreted as host:port
493              msg = f"Error: Invalid port specified in -proxy: 'unix:{'x' * 1000}'"
494          self.nodes[1].assert_start_raises_init_error(expected_msg=msg)
495  
496          # Cleanup socket path we established outside the individual test directory.
497          if self.have_unix_sockets:
498              os.unlink(socket_path)
499  
500  if __name__ == '__main__':
501      ProxyTest(__file__).main()