spesmilo / electrum

Electrum Bitcoin Wallet
https://electrum.org
MIT License
7.35k stars 3.06k forks source link

cannot connect to Tor hidden service (onion) over Transparent Proxy (proxy needs to be explicitly configured in Electrum) #6081

Open otaviobonder-deel opened 4 years ago

otaviobonder-deel commented 4 years ago

I'm running Electrum Personal Server on my server, over Tor. I can connect to it if I launch Tor on my client PC and configure Electrum to use SOCKS5.

I have, however, a VPN server that routes all traffic to the Tor network. The scheme is this:

VPN Client -> VPN Server -> Tor -> Internet

DNS and iptables are all configured correctly on the server, and I forward all traffic on my client PC to the Tor network. In other words, I can access the Tor network running just my VPN on my client PC.

Electrum, however, won't connect to my EPS server over Tor. What I did was disable the SOCKS5 option, and set the server address my .onion server address. Since my VPN is routing all traffic thru Tor, Electrum should be able to connect to the onion server.

Electrum log shows:

20200412T150538.412831Z |     INFO | network | couldn't launch iface http://xxxxxxxxxx.onion:50002:t -- CancelledError()
20200412T150539.024810Z |     INFO | network | connecting to http://xxxxxxxxxx.onion:50002:t as new interface
20200412T150539.128121Z |     INFO | interface.[http://xxxxxxxxx.onion:50002] | disconnecting due to: ConnectError(gaierror(8, 'nodename nor servname provided, or not known'),)

Inspecting my network packages, I can't see any DNS call from Electrum, so how does it discover the host IP if it doesn't make any DNS call?

SomberNight commented 4 years ago
20200412T150538.412831Z |     INFO | network | couldn't launch iface http://xxxxxxxxxx.onion:50002:t -- CancelledError()
20200412T150539.024810Z |     INFO | network | connecting to http://xxxxxxxxxx.onion:50002:t as new interface
20200412T150539.128121Z |     INFO | interface.[http://xxxxxxxxx.onion:50002] | disconnecting due to: ConnectError(gaierror(8, 'nodename nor servname provided, or not known'),)

The Electrum protocol does not use HTTP, so this looks weird. Also, just a note that typically port 50002 is used for SSL/TLS connections, while port 50001 is used for plaintext TCP (although these are just defaults), so are you sure the port is correct?

How are you specifying the server to Electrum?

SomberNight commented 4 years ago

What OS is the client running on btw?

otaviobonder-deel commented 4 years ago

EPS is running on Debian 10 and Electrum is running on MacOS.

I have another server running Electrs and I can connect to it when running Electrum with the SOCKS proxy enabled.

When I try to run Electrum without SOCKS but connected to the VPN server, same error occur:

20200412T180756.008315Z |     INFO | network | connecting to xxxxxxxx.onion:50001:t as new interface
20200412T180756.116011Z |     INFO | interface.[xxxxxxxx.onion:50001] | disconnecting due to: ConnectError(gaierror(8, 'nodename nor servname provided, or not known'),)
20200412T180756.119670Z |     INFO | network | couldn't launch iface xxxxxxxx.onion:50001:t -- CancelledError()
SomberNight commented 4 years ago

Open a Python interpreter and run:

import socket
socket.getaddrinfo("bbcnewsv2vjtpsuy.onion", 80)

Does that raise an exception or what happens?

Without even trying to set up an onion resolver,


Note: this is the trace I get if I try to connect to an onion server without a proxy set up inside Electrum (on Windows):

I/i | interface.[wsw6tua3xl24gsmi264zaep6seppjyrkyucpsmuxnjzyt3f3j6swshad.onion:50002] | disconnecting due to: ConnectError(gaierror(11001, 'getaddrinfo failed'))
E/i | interface.[wsw6tua3xl24gsmi264zaep6seppjyrkyucpsmuxnjzyt3f3j6swshad.onion:50002] | trace
Traceback (most recent call last):
  File "...\electrum\electrum\interface.py", line 195, in create_connection
    return await super().create_connection()
  File "...\aiorpcX\aiorpcx\rawsocket.py", line 162, in create_connection
    return await connector.create_connection(
  File "...\Python38\lib\asyncio\base_events.py", line 986, in create_connection
    infos = await self._ensure_resolved(
  File "...\Python38\lib\asyncio\base_events.py", line 1365, in _ensure_resolved
    return await loop.getaddrinfo(host, port, family=family, type=type,
  File "...\Python38\lib\asyncio\base_events.py", line 825, in getaddrinfo
    return await self.run_in_executor(
  File "...\Python38\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "...\Python38\lib\socket.py", line 918, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 11001] getaddrinfo failed
SomberNight commented 4 years ago

I was thinking something like this could work:

import socket
socket.getaddrinfo = lambda *args: [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))] if args[0].endswith('.onion') else socket._getaddrinfo(*args)

But no, see e.g. trace:

Traceback (most recent call last):
  File "...\electrum\electrum\lnpeer.py", line 459, in _message_loop
    await asyncio.wait_for(self.initialize(), LN_P2P_NETWORK_TIMEOUT)
  File "...\Python38\lib\asyncio\tasks.py", line 483, in wait_for
    return fut.result()
  File "...\electrum\electrum\lnpeer.py", line 129, in initialize
    await self.transport.handshake()
  File "...\electrum\electrum\lntransport.py", line 235, in handshake
    self.reader, self.writer = await asyncio.open_connection(self.peer_addr.host, self.peer_addr.port)
  File "...\Python38\lib\asyncio\streams.py", line 52, in open_connection
    transport, _ = await loop.create_connection(
  File "...\Python38\lib\asyncio\base_events.py", line 1025, in create_connection
    raise exceptions[0]
  File "...\Python38\lib\asyncio\base_events.py", line 1010, in create_connection
    sock = await self._connect_sock(
  File "...\Python38\lib\asyncio\base_events.py", line 924, in _connect_sock
    await self.sock_connect(sock, address)
  File "...\Python38\lib\asyncio\proactor_events.py", line 702, in sock_connect
    return await self._proactor.connect(sock, address)
  File "...\Python38\lib\asyncio\windows_events.py", line 592, in connect
    ov.ConnectEx(conn.fileno(), address)
OSError: [WinError 10022] An invalid argument was supplied

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "...\electrum\electrum\lnpeer.py", line 251, in wrapper_func
    return await func(self, *args, **kwargs)
  File "...\electrum\electrum\lnpeer.py", line 270, in main_loop
    await group.spawn(self.process_gossip())
  File "...\aiorpcX\aiorpcx\curio.py", line 242, in __aexit__
    await self.join()
  File "...\aiorpcX\aiorpcx\curio.py", line 211, in join
    raise task.exception()
  File "...\electrum\electrum\lnpeer.py", line 461, in _message_loop
    raise GracefulDisconnect(f'initialize failed: {repr(e)}') from e
electrum.interface.GracefulDisconnect: initialize failed: OSError(10022, 'An invalid argument was supplied', None, 10022, None)