Search code examples
rubytorsockstorsocks

Ruby Tor Switching Ip - "general SOCKS server failure" unless I spawn a new process to telnet into Tor control port


When trying to switch Tor IP address using telnet, I am running into SOCKSError::ServerFailure: general SOCKS server failure when trying to connect to the Tor control port via telnet. However if I spawn a new process to do the telnetting, I have no problem. I dont want to spawn a new process because its ugly. I was hoping someone could help me find why I have this problem and a more rubust solution?

To reproduce:

start tor:

tor --SocksPort 9350 --ControlPort 53500 --CookieAuthentication 0 --HashedControlPassword <passwordhash> --DataDirectory /tmp/tor_data/9350

Then run this ruby code which uses socksify to setup a socks server, then uses the tor gem Tor::Controller.connect block which connects to the Tor control port via telnet to switch Tor endpoint:

require 'socksify'
require 'terminator'
require 'tor'

TCPSocket::socks_server = "127.0.0.1"
TCPSocket::socks_port = "9350"

Tor::Controller.connect(:port => 53500) do |tor| #<- error
  tor.authenticate("")
  tor.signal("newnym")
end

Error at Tor::Controller.connect call:

SOCKSError::ServerFailure: general SOCKS server failure

If I replace the Tor::Controller.connect block with this (spawning a new process to do the telnetting), I have success:

telnet_pid = nil
begin
  Terminator.terminate :seconds => 20 do
    cmd = "bundle exec ruby -e \"require 'tor'\" -e " +
          "\"Tor::Controller.connect(:port => 53500)" +
          "{|tor| tor.authenticate(''); tor.signal('newnym')}\""
    telnet_pid = Process.spawn(cmd)
    Process.wait telnet_pid
  end
rescue Terminator.error
  puts 'Telnet process to switch Tor endpoint timed out!'
  Process.kill('TERM', telnet_pid) if telnet_pid
end

Solution

  • I realised that the socks server was routing all TCP requests through the SOCKS server including my telnet requests. If I disable the socks server while telnetting then re-enable it again it works:

    TCPSocket::socks_server = nil
    TCPSocket::socks_port = nil
    
    Tor::Controller.connect(:port => 53500) do |tor| #<- error
      tor.authenticate("")
      tor.signal("newnym")
    end
    
    TCPSocket::socks_server = "127.0.0.1"
    TCPSocket::socks_port = "9350"