I recently tried to use the ELinks console-based web browser with Tor. I found what seemed to be the easiest way to this: torify elinks, but that turned into a journey down the rabbit-hole. (A wiser man than I likely would’ve just used the alternate method suggested there—privoxy—but for the next one of me who comes along, here’s what I found.)
The first issue I ran into was that elinks didn’t seem to be going through the proxy defined by LD_PRELOAD / torsocks config (verified by the inability to resolve .onion addresses and a what-is-my-ip page check). That solution, stupidly enough, was to exit the other instance of elinks that I had running. I suppose that because of the use of shared libraries, solutions like this are a first-come-first-serve deal.
Getting past that, I ran into the real issue: regular web traffic was going through tor, but attempting to resolve *.onion addresses resulted in failure and a few of these warnings:
My normal approach of searching for help didn’t turn up anything useful for that warning or queries like ‘torsocks elinks’ or ‘torify elinks’ or ‘elinks dns’, so I put on my hard-hat and went to work. The first order of business was to turn up the volume. From the torsocks(8) manpage, I learned I could get some more debug messages like this:
After reproducing the error, I dug into the log file and found this interesting excerpt (.onion address changed):
[Aug 19 14:23:51] DEBUG torsocks: [getaddrinfo] Requesting SPGmA7pu1CsgVBNW.onion hostname (in tsocks_getaddrinfo() at getaddrinfo.c:44) [Aug 19 14:23:51] DEBUG torsocks: Resolving SPGmA7pu1CsgVBNW.onion on the Tor network (in tsocks_tor_resolve() at torsocks.c:527) [Aug 19 14:23:51] DEBUG torsocks: [onion] Finding onion entry for name SPGmA7pu1CsgVBNW.onion (in onion_entry_find_by_name() at onion.c:229) [Aug 19 14:23:51] DEBUG torsocks: [onion] Creating onion entry for name SPGmA7pu1CsgVBNW.onion (in onion_entry_create() at onion.c:174) [Aug 19 14:23:51] DEBUG torsocks: [onion] Entry added to the onion pool at index 0 (in insert_onion_entry() at onion.c:79) [Aug 19 14:23:51] DEBUG torsocks: [onion] Entry added with IP address 127.42.42.0 used as cookie (in onion_entry_create() at onion.c:207) [Aug 19 14:23:51] DEBUG torsocks: [getaddrinfo] Node SPGmA7pu1CsgVBNW.onion resolved to 127.42.42.0 (in tsocks_getaddrinfo() at getaddrinfo.c:107) [Aug 19 14:23:51] DEBUG torsocks: Close catched for fd 10 (in tsocks_close() at close.c:33) [Aug 19 14:23:51] DEBUG torsocks: [onion] Destroying onion pool containing 1 entry (in onion_pool_destroy() at onion.c:148) [Aug 19 14:23:51] DEBUG torsocks: [fclose] Close catched for fd 4 (in tsocks_fclose() at fclose.c:45) [Aug 19 14:23:51] DEBUG torsocks: Close catched for fd 9 (in tsocks_close() at close.c:33) [Aug 19 14:23:51] DEBUG torsocks: [socket] Creating socket with domain 2, type 1 and protocol 6 (in tsocks_socket() at socket.c:33) [Aug 19 14:23:51] DEBUG torsocks: Connect catched on fd 9 (in tsocks_connect() at connect.c:112) [Aug 19 14:23:51] DEBUG torsocks: [connect] Socket family AF_INET and type 1 (in validate_socket() at connect.c:77) [Aug 19 14:23:51] DEBUG torsocks: [onion] Finding onion entry for IP 127.42.42.0 (in onion_entry_find_by_addr() at onion.c:268) [Aug 19 14:23:51] WARNING torsocks: [connect] Connection to a local address are denied since it might be a TCP DNS query to a local DNS server. Rejecting it for safety reasons. (in tsocks_connect() at connect.c:186)
I’ll save you some of the details, since they’re long and boring, but after looking through source code for both torsocks and elinks, I eventually discovered that elinks [apparently] resolves hostnames asynchronously by default. Torsocks doesn’t maintain its onion ‘pool’ (a struct with protections for atomic access, containing an array mapping fake IP addresses (‘cookies’) to their hidden service *.onion hostname) between instances, so when elinks resolves the IP address for blah.onion in another thread, and then passes back the address ‘127.42.42.0’ to the thread trying to create the HTTP socket (the actual TCP request), it fails. The torsocks instance (private memory space) for the http thread has no record of the ‘127.42.42.0 = blah.onion’ mapping, which is needed for the connection to go through, and thus it fails.
Like a typical FOSS user, I took the easy way out instead of actually working on a way to correct the
issue in torsocks (it’s better to do this than share system-wide, so may be a
feature, but I think it should still be shared/cached per-user). My workaround was to disable asynchronous DNS lookups in elinks in my ~/.elinks/elinks.conf as follows: