ElementsProject / lightning

Core Lightning — Lightning Network implementation focusing on spec compliance and performance
Other
2.79k stars 880 forks source link

Using Tor without a proxy #6691

Open tmpgithubissue102 opened 9 months ago

tmpgithubissue102 commented 9 months ago

We run our cryptocurrency nodes on isolated machines that use an external network gateway to route all their traffic to Tor (Whonix Gateway), where any DNS requests for .onion addresses are automaticaly mapped to local addresses by the Tor instance running at the gateway (see Tor's TransPort, DNSPort and AutomapHostsOnResolve in case you are unfamiliar with such configurations).

Currently it's problematic to run CLN on a such setup because CLN assumes that .onion addresses can be only resolved and used via proxy, since any attempts to connect to an .onion node result into the error "need a proxy", considering that other applications on the same system have no issues resolving and connecting directly to .onion hosts.

Taking a brief look at this part from connectd/connectd.c confirms that, because it forces setting use_proxy to true when the hostname is an .onion address:

    case ADDR_INTERNAL_FORPROXY:
        use_proxy = true;
        break;
    case ADDR_INTERNAL_WIREADDR:
        switch (addr->u.wireaddr.wireaddr.type) {
        case ADDR_TYPE_TOR_V2_REMOVED:
            af = -1;
            break;
        case ADDR_TYPE_TOR_V3:
            use_proxy = true;
            break;

The use case of CLN on a machine fully routed by Tor was overlooked.

Furthermore, the only suitable case described by the documentation at https://docs.corelightning.org/docs/tor also doesn't presume a Tor instance can be used by routing connections to it instead of using its SocksPort:

Case #4: Unannounced IP address, and a fixed Tor address in torrc

addr=statictor:127.0.0.1:9051
proxy=127.0.0.1:9050
always-use-proxy=true

This issue can be resolved by stopping enforcing the use_proxy flag automatically and letting a system's resolver to handle .onion addresses.

tmpgithubissue102 commented 9 months ago

This is a temporary patch for the case ADDR_TYPE_TOR_V3: switch case at https://github.com/ElementsProject/lightning/blob/v23.08.1/connectd/connectd.c#L827 that allowed me to run my node as intended:

        case ADDR_TYPE_TOR_V3:
            if (use_proxy) /* hand it to the proxy */
                break;
            if (!use_dns) {  /* ignore DNS when we can't use it */
                tal_append_fmt(&connect->errors,
                           "%s: dns disabled. ",
                           type_to_string(tmpctx,
                                  struct wireaddr_internal,
                                  addr));
                goto next;
            }
            /* Resolve with getaddrinfo */
            memset(&hints, 0, sizeof(hints));
            hints.ai_socktype = SOCK_STREAM;
            hints.ai_family = AF_UNSPEC;
            hints.ai_protocol = 0;
            hints.ai_flags = AI_ADDRCONFIG;
            gai_err =  getaddrinfo(fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr.wireaddr), // use fmt_wireaddr_without_port() to extract the .onion hostname
                          tal_fmt(tmpctx, "%d",
                              addr->u.wireaddr.wireaddr.port),
                          &hints, &ais); 
            if (gai_err != 0) {
                tal_append_fmt(&connect->errors,
                           "%s: getaddrinfo error '%s'. ",
                           type_to_string(tmpctx,
                                  struct wireaddr_internal,
                                  addr),
                           gai_strerror(gai_err));
                goto next;
            }
            /* create new addrhints on-the-fly per result ... */
            for (aii = ais; aii; aii = aii->ai_next) {
                addrhint.itype = ADDR_INTERNAL_WIREADDR;
                addrhint.u.wireaddr.is_websocket = false;
                if (aii->ai_family == AF_INET) {
                    sa4 = (struct sockaddr_in *) aii->ai_addr;
                    wireaddr_from_ipv4(&addrhint.u.wireaddr.wireaddr,
                               &sa4->sin_addr,
                               addr->u.wireaddr.wireaddr.port);
                } else if (aii->ai_family == AF_INET6) {
                    sa6 = (struct sockaddr_in6 *) aii->ai_addr;
                    wireaddr_from_ipv6(&addrhint.u.wireaddr.wireaddr,
                               &sa6->sin6_addr,
                               addr->u.wireaddr.wireaddr.port);
                } else {
                    /* skip unsupported ai_family */
                    continue;
                }
                tal_arr_expand(&connect->addrs, addrhint);
                /* don't forget to update convenience pointer */
                addr = &connect->addrs[connect->addrnum];
            }
            freeaddrinfo(ais);
            goto next;

The code was copied from the case ADDR_TYPE_DNS: switch case (https://github.com/ElementsProject/lightning/blob/v23.08.1/connectd/connectd.c#L836) and modified to resolve the .onion domain instead.

Running a patched node for a week with some open channels without any connectivity issues, having both clearnet and Tor connections to peers.

Not closing the issue because the main CLN's repository continues with a broken logic for handling .onion addresses in connectd.c and I expect some maintainer/contributor to make a cleaner patch. Note that always-use-proxy should determine whether to enforce use-proxy or not in that particular situation.

marcovelon commented 8 months ago

I wanted to try Lightning and came across this issue here.

First of all, thank you @tmpgithubissue102 for providing a patch that helped me to avoid wasting time on debugging the issue myself. It works as expected.

Secondly, I am not sure why the 'bug' tag wasn't assigned yet, since it's not about personal preferences here but about how software is supposed to work by default - without assuming there is a need of a proxy if we need to resolve an .onion address, since Tor instance is capable of being a standalone router and has appropriate configurations for routing the network traffic through itself.

Core Lightning refuses to resolve .onion addresses if there is no proxy specified, which is a bug.

@cdecker @rustyrussell @vincenzopalazzo hope you can clarify this.