Tor Manager

Ruby gem that provides a Tor interface with functionality:

  • Start and stop and monitor a Tor process. The Tor Process is monitored using Eye.
  • Retrieve the current Tor IP address and get new ip address upon request.
  • Proxy web client requests through Tor.

Installation

Install Tor:

sudo apt-get install tor

Add this line to your application's Gemfile:

gem 'tormanager'

And then execute:

$ bundle

Or install it yourself as:

$ gem install tormanager

Usage

Tor Process

This section shows how to start, stop and manage Tor processes.

Start a Tor process with default settings:

require 'tormanager'

tor_process = TorManager::TorProcess.new
tor_process.start

#you can get the control password for the Tor process if you want: 
tor_process.settings[:control_password]

By default, the Tor process will use using port 9050 and control port 50500 and will be spawned using Eye ensuring that the process remains in a healthy state. Eye will generate a config file based on the default template. Eye will invoke the Tor process with command which looks like this:

tor --SocksPort 9050 --ControlPort 50500 --CookieAuthentication 0 --HashedControlPassword "<hashedpassword from the :control_password>" --NewCircuitPeriod 60

Eye will restart the Tor process if a cpu percentage exceeds 10% for 3 consecutive readings (checked every 30 seconds). Eye will restart the Tor process if its memory exceeds 200MB for 3 consecutive readings (checked every 60 seconds). By default, will do minimal logging and will create a random :control_password which is used to generate the HashedControlPassword used to change the Tor password on request. More information can be found in the TorManager::TorProcess parameters table below.

You can also spawn a Tor process with control over parameters:

tor_process = 
  TorManager::TorProcess.new tor_port: 9051, 
                             control_port: 50501, 
                             pid_dir: '/my/pid/dir',
                             log_dir: '/my/log/dir',
                             tor_data_dir: '/my/tor/datadir',
                             tor_new_circuit_period: 120,
                             max_tor_memory_usage_mb: 400,
                             max_tor_cpu_percentage: 15,
                             control_password: 'mycontrolpass',
                             eye_logging: true,
                             tor_logging: true
tor_process.start

See the table below for more info.

When done with the Tor process, stop it:

tor_process.stop 

The following table describes the TorManager::TorProcess parameters:

Parameter Default Value Description
:tor_port 9050 The listening port of the Tor process.
:control_port 50500 The control port of the Tor process.
:pid_dir /tmp Eye will create a pid file in this location which stores the pid of the Tor process. The name of the pid file is of format: tormanager-tor-<tor_port>-<parent_pid>.pid .
:log_dir /tmp If :eye_logging is true, Eye will create a log (tormanager.eye.log) in this location. If :tor_logging is true, Tor stdall is redirected to log (tormanager-tor-<tor_port>-<parent_pid>.log ) in this location.
:tor_data_dir nil If specified, Tor will use this directory location as the --DataDirectory.
:tor_new_circuit_period 60 In seconds, specifies the --NewCircuitPeriod that Tor should use.
:max_tor_memory_usage_mb 200 In megabytes, Eye will restart the Tor process if its memory exceeds this value for 3 consecutive readings (checked every 60 seconds).
:max_tor_cpu_percentage 10 Percentage value, Eye will restart the Tor process if it's cpu percentage exceeds this value for 3 consecutive readings (checked every 30 seconds).
:eye_tor_config_template tormanager/eye/tor.template.eye.rb Specify your own eye config template, it is recommended to use the default template as your starting point.
:control_password Randomly generated by default. By default, will do minimal logging and will create a random :control_password which is used to generate the HashedControlPassword used to change the Tor password on request.
:tor_log_switch nil If specified, sets the Tor --Log switch, for example a value of notice syslog will add --Log "notice syslog" to the Tor command.
:eye_logging nil If set to true will enable Eye logging in the :log_dir location, eye log: tormanager.eye.log
:tor_logging nil If set to true, Tor stdall is redirected to log (tormanager-tor-<tor_port>-<parent_pid>.log ) in this location.
:dont_remove_tor_config nil By default, an eye configuration file is generated for the current Tor instance based on the :eye_tor_config_template stored in the :log_dir with name tormanager.tor.<tor_port>.<parent_pid>.eye.rb . This generated file is removed when the Tor process is stopped by default. Setting :dont_remove_tor_config to true will not remove this file.

where <tor_port> is the :tor_port of the Tor process and <parent_pid> is the pid of the ruby process spawning the Tor process.

To stop any Tor instances that have been previously started by Tor Manager but were not stopped (say in the event of a parent process crash) ††:

TorManager::TorProcess.stop_obsolete_processes 

Query whether Tor Manager has any Tor processes running on a particular port ††:

TorManager::TorProcess.tor_running_on? port: 9050 

Query whether Tor Manager has any Tor processes running on a particular port associated to a particular parent ruby pid ††:

TorManager::TorProcess.tor_running_on? port: 9050, parent_pid: 12345

†† Note that this command applies only to Tor processes that were started by Tor Manager. Tor processes that have been started external to Tor Manager will not be impacted.

Proxy Through Tor, Query IP Address, Change IP Address

Once you have a TorProcess started, you can:

The remaining examples assume that you have instantiated a TorProcess ie:

tor_process = TorManager::TorProcess.new
tor_process.start

Proxy Through Tor

tor_proxy = TorManager::Proxy.new tor_process: tor_process 
tor_proxy.proxy do 
  tor_ip = RestClient::Request.execute(
             method: :get,
             url: 'http://bot.whatismyipaddress.com').to_str
end
my_ip = RestClient::Request.execute(
             method: :get,
             url: 'http://bot.whatismyipaddress.com').to_str

Note that in the above code the RestClient::Request returning tor_ip is routed through the Tor endpoint because it is yielded through the TorManager::Proxy#proxy block. The following request returning my_ip will not be routed through the Tor endpoint hence returning your current IP address.

You could route Capybara requests through the proxy (just make sure you use the :poltergeist driver and set the proxy to use the Tor socks proxy):

Capybara.default_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, {
    :phantomjs => Phantomjs.path,
    :phantomjs_options => ["--proxy-type=socks5", "--proxy=127.0.0.1:9050"]
  })
end
tor_proxy = TorManager::Proxy.new tor_process: tor_process 
tor_proxy.proxy do 
  tor_ip = Capybara.visit('http://bot.whatismyipaddress.com').text
end

Query IP Address

Query the Tor endpoint for the current IP address:

tor_proxy = TorManager::Proxy.new tor_process: tor_process  
tor_ip_control = 
  TorManager::IpAddressControl.new tor_process: tor_process, 
                                   tor_proxy: tor_proxy 
tor_ip_control.get_ip                                      

When the TorManager::IpAddressControl#get_ip method is called, the IP address is stored in instance variable:

tor_ip_control.ip 

Change IP Address

Get a new IP address:

tor_proxy = TorManager::Proxy.new tor_process: tor_process  
tor_ip_control = 
  TorManager::IpAddressControl.new tor_process: tor_process, 
                                   tor_proxy: tor_proxy 
tor_ip_control.get_new_ip                                      

When the TorManager::IpAddressControl#get_new_ip method is called, the IP address is stored in instance variable:

tor_ip_control.ip

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/joshweir/tormanager.

License

The gem is available as open source under the terms of the MIT License.