class Tor::Controller

Tor Control Protocol (TC) client.

The Tor control protocol is used by other programs (such as frontend user interfaces) to communicate with a locally running Tor process. It is not part of the Tor onion routing protocol.

@example Establishing a controller connection (1)

tor = Tor::Controller.new

@example Establishing a controller connection (2)

tor = Tor::Controller.new(:host => '127.0.0.1', :port => 9051)

@example Authenticating the controller connection

tor.authenticate

@example Obtaining information about the Tor process

tor.version      #=> "0.2.1.25"
tor.config_file  #=> #<Pathname:/opt/local/etc/tor/torrc>

@see gitweb.torproject.org/tor.git?a=blob_plain;hb=HEAD;f=doc/spec/control-spec.txt @see www.thesprawl.org/memdump/?entry=8 @since 0.1.1

Constants

PROTOCOL_VERSION

Attributes

host[R]
port[R]

Public Class Methods

connect(options = {}, &block) click to toggle source

@param [Hash{Symbol => Object}] options @option options [String, to_s] :host (“127.0.0.1”) @option options [Integer, to_i] :port (9051) @option options [String, to_s] :cookie (nil) @option options [Integer, to_i] :version (PROTOCOL_VERSION)

# File lib/tor/control.rb, line 36
def self.connect(options = {}, &block)
  if block_given?
    result = block.call(tor = self.new(options))
    tor.quit
    result
  else
    self.new(options)
  end
end
new(options = {}, &block) click to toggle source

@param [Hash{Symbol => Object}] options @option options [String, to_s] :host (“127.0.0.1”) @option options [Integer, to_i] :port (9051) @option options [String, to_s] :cookie (nil) @option options [Integer, to_i] :version (PROTOCOL_VERSION)

# File lib/tor/control.rb, line 52
def initialize(options = {}, &block)
  @options = options.dup
  @host    = (@options.delete(:host)    || '127.0.0.1').to_s
  @port    = (@options.delete(:port)    || 9051).to_i
  @version = (@options.delete(:version) || PROTOCOL_VERSION).to_i
  connect
  if block_given?
    block.call(self)
    quit
  end
end

Public Instance Methods

authenticate(cookie = nil) click to toggle source

Authenticates the controller connection.

@example

C: AUTHENTICATE
S: 250 OK

@example

tor.authenticate

@return [void] @raise [AuthenticationError] if authentication failed

# File lib/tor/control.rb, line 191
def authenticate(cookie = nil)
  cookie ||= @options[:cookie]
  send(:send_line, cookie ? "AUTHENTICATE #{cookie}" : "AUTHENTICATE")
  case reply = read_reply
    when '250 OK' then @authenticated = true
    else raise AuthenticationError.new(reply)
  end
  self
end
authenticated?() click to toggle source

Returns `true` if the controller connection has been authenticated.

@example

tor.authenticated?         #=> false
tor.authenticate
tor.authenticated?         #=> true

@return [Boolean]

# File lib/tor/control.rb, line 175
def authenticated?
  @authenticated || false
end
authentication_method() click to toggle source

Returns information about the authentication method required by the Tor process.

This command may be used before authenticating.

@example

C: PROTOCOLINFO
S: 250-PROTOCOLINFO 1
S: 250-AUTH METHODS=NULL
S: 250-VERSION Tor="0.2.1.25"
S: 250 OK

@example

tor.authentication_method  #=> nil
tor.authentication_method  #=> :hashedpassword
tor.authentication_method  #=> :cookie

@return [Symbol] @since 0.1.2

# File lib/tor/control.rb, line 148
def authentication_method
  @authentication_method ||= begin
    method = nil
    send_line('PROTOCOLINFO')
    loop do
      # TODO: support for reading multiple authentication methods
      case reply = read_reply
        when /^250-AUTH METHODS=(\w*)/
          method = $1.strip.downcase.to_sym
          method = method.eql?(:null) ? nil : method
        when /^250-/  then next
        when '250 OK' then break
      end
    end
    method
  end
end
close() click to toggle source

Closes the socket connection to the Tor process.

@example

tor.close

@return [void]

# File lib/tor/control.rb, line 101
def close
  @socket.close if @socket
  @socket = nil
  self
end
config_file() click to toggle source

Returns the path to the Tor configuration file.

@example

C: GETINFO config-file
S: 250-config-file=/opt/local/etc/tor/torrc
S: 250 OK

@example

tor.config_file            #=> #<Pathname:/opt/local/etc/tor/torrc>

@return [Pathname]

# File lib/tor/control.rb, line 232
def config_file
  send_command(:getinfo, 'config-file')
  reply = read_reply.split('=').last
  read_reply # skip "250 OK"
  Pathname(reply)
end
config_text() click to toggle source

Returns the current (in-memory) Tor configuration. Response is terminated with a “.”

@example

C: GETINFO config-text
S: 250+config-text=
S: ControlPort 9051
S: RunAsDaemon 1
S: .
# File lib/tor/control.rb, line 249
def config_text
  send_command(:getinfo, 'config-text')
  reply = ""
  read_reply # skip "250+config-text="
  while line = read_reply
    break unless line != "."
    reply.concat(line + "\n")
  end
  read_reply # skip "250 OK"
  return reply
end
connect() click to toggle source

Establishes the socket connection to the Tor process.

@example

tor.close
tor.connect

@return [void]

# File lib/tor/control.rb, line 74
def connect
  close
  @socket = TCPSocket.new(@host, @port)
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
  self
end
connected?() click to toggle source

Returns `true` if the controller connection is active.

@example

tor.connected?             #=> true
tor.close
tor.connected?             #=> false

@return [Boolean]

# File lib/tor/control.rb, line 90
def connected?
  !!@socket
end
quit() click to toggle source

Tells the Tor process to hang up on this controller connection.

This command can be used before authenticating.

@example

C: QUIT
S: 250 closing connection
^D

@example

tor.quit

@return [void]

# File lib/tor/control.rb, line 121
def quit
  send_line('QUIT')
  reply = read_reply
  close
  reply
end
signal(name) click to toggle source

Send a signal to the server

@example tor.signal(“newnym”)

@return [String]

# File lib/tor/control.rb, line 268
def signal(name)
  send_command(:signal, name)
  read_reply
end
version() click to toggle source

Returns the version number of the Tor process.

@example

C: GETINFO version
S: 250-version=0.2.1.25
S: 250 OK

@example

tor.version                #=> "0.2.1.25"

@return [String]

# File lib/tor/control.rb, line 213
def version
  send_command(:getinfo, 'version')
  reply = read_reply.split('=').last
  read_reply # skip "250 OK"
  reply
end

Protected Instance Methods

read_reply() click to toggle source

Reads a reply line from the socket.

@return [String]

# File lib/tor/control.rb, line 300
def read_reply
  @socket.readline.chomp
end
send_command(command, *args) click to toggle source

Sends a command line over the socket.

@param [Symbol, to_s] command @param [Array<String>] args @return [void]

# File lib/tor/control.rb, line 281
def send_command(command, *args)
  authenticate unless authenticated?
  send_line(["#{command.to_s.upcase}", *args].join(' '))
end
send_line(line) click to toggle source

Sends a text line over the socket.

@param [String, to_s] line @return [void]

# File lib/tor/control.rb, line 291
def send_line(line)
  @socket.write(line.to_s + "\r\n")
  @socket.flush
end