Class: Tor::TController
- Inherits:
-
Controller
- Object
- Controller
- Tor::TController
- Defined in:
- lib/tcontroller.rb
Overview
Tor:TController is an extension of the Tor::Controller class, providing more methods.
It inherits all methods from Tor::Controller and can be used to interact with Tor.
<b>TController examples</b>
require 'tor_extend'
Tor::TController.new(:host=>@getbridge_config[:torcontrolhost],
:port=>@getbridge_config[:torcontrolport])
Tor::TController.new(:host=>"127.0.0.1",:port=>9051)
Tor::TController.connect
Tor::TController.authenticate("\"tor_control_password\"")
Tor::TController.sr(:signal,"HUP")
Tor::TController.sr(:signal,"newnym")
Tor::TController.getinfo("ns/all")
Tor::TController.net_status
Tor::TController.closecircuit(15)
Tor::TController.closeallcircuits
Tor::TController.signal("reload"
Tor::TController.extendcir(0,['or1','or2','or3'])
Tor::TController.setconf("__DisablePredictedCircuits",1)
Tor::TController.setconf("__LeaveStreamsUnattached",1)
Tor::TController.getconf("ORPort")
Tor::TController.getconf("__LeaveStreamsUnattached")
Tor::TController.get_bridges( {:type=>'http',:port=>9050,:addr=>'127.0.0.1'} )
For more details, visit [https://github.com/bendiken/tor-ruby#readme], [https://gitweb.torproject.org/torspec.git/tree]
Instance Method Summary collapse
-
#attach_stream(stream_no, cir_num, *hop_count) ⇒ Object
This attaches streams to circuits.
-
#bridges ⇒ Object
Returns all the brdiges in the database as an array.
-
#cir_status ⇒ Object
This returns the circuit-status in an array, or an empty array on failure.
-
#closeallcircuits ⇒ Object
This attempts to close all open circuits.
-
#closecircuit(circnum) ⇒ Object
This attempts to close a single circuit.
-
#ds ⇒ Object
Returns the an array of of directory servers from the consensus.
-
#extendcir(circnum, or_list) ⇒ Object
Creating a new circuit.
-
#extendcir_slowly(orarray) ⇒ Object
This builds a circuit to each member of the array argument, skipping any node that fails to connect.
-
#get_bridges(cacheddesc, *config) ⇒ Object
Tor::TController.get_bridges( :proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0.0:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0.0.1’ ).
-
#get_entryguards ⇒ Object
Get entry-guards.
- #get_httperrors ⇒ Object
-
#get_purposeip(nodetype) ⇒ Object
This gets the IP addresses for ORs based on the characteristics of the OR.
-
#getconf(confname) ⇒ Object
For more details, see [gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt].
-
#getinfo(*args) ⇒ Object
This method sends the “GETINFO” protocol message with the arguments.
-
#initialize(options = {}, &block) ⇒ TController
constructor
A new instance of TController.
-
#net_status ⇒ Object
This returns an array of hash tables with the fingerprints of all onion routers that have not been marked as down.
-
#newstreams ⇒ Object
This returns all the new streams that have not been assigned to a circuit.
-
#setconf(confname, value) ⇒ Object
Tor::TController.setconf(“__DisablePredictedCircuits”,1) =>[“OK”, []] Tor::TController.setconf(“__LeaveStreamsUnattached”,1) =>[“OK”, []] Tor::TController.setconf(“ORPort”,9001) =>[“OK”, []].
-
#signal(args) ⇒ Object
This method sends “signals” protocol message with the arguments.
-
#sr(command, *args) ⇒ Object
This sends commands and returns the protocol response code along with an array containing the results with the following format [errorcode,].
Constructor Details
#initialize(options = {}, &block) ⇒ TController
Returns a new instance of TController.
42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/tcontroller.rb', line 42 def initialize( = {}, &block) @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 @passwd = (@options.delete(:password) || '').to_s connect authenticate "\"#{@passwd}\"" if ! @passwd != "" if block_given? block.call(self) quit end end |
Instance Method Details
#attach_stream(stream_no, cir_num, *hop_count) ⇒ Object
This attaches streams to circuits. No documentation yet.
266 267 268 269 270 271 272 273 |
# File 'lib/tcontroller.rb', line 266 def attach_stream(stream_no, cir_num ,*hop_count) # puts "attachstream #{cir_num}\n" if hop_count.empty? or hop_count[0] == 0 sr(:attachstream,"#{stream_no} #{cir_num}") else sr(:attachstream,"#{stream_no} #{cir_num} HOP=#{hop_count[0]}") end end |
#bridges ⇒ Object
Returns all the brdiges in the database as an array.
Tor::TController.bridges => [{:ipaddr, :port, :lat, :lng},...]
248 249 250 |
# File 'lib/tcontroller.rb', line 248 def bridges Bridges.all end |
#cir_status ⇒ Object
This returns the circuit-status in an array, or an empty array on failure
<b>Get the circuit-status from Tor</b>.
Tor::TController.cir_status
["46 BUILT ORa,ORb,ORc PURPOSE=GENERAL"]
63 64 65 |
# File 'lib/tcontroller.rb', line 63 def cir_status cirstatus=getinfo("circuit-status") end |
#closeallcircuits ⇒ Object
This attempts to close all open circuits.
<b>Closing all circuits</b>
Tor::TController.closeallcircuits
81 82 83 84 85 86 87 88 89 |
# File 'lib/tcontroller.rb', line 81 def closeallcircuits x=cir_status if !x.empty? x.each{|eachcircuit| circnum = eachcircuit.match(/^\d+/) closecircuit(circnum) } end end |
#closecircuit(circnum) ⇒ Object
This attempts to close a single circuit.
<b>Closing circuits</b>
Tor::TController.closecircuit(15)
72 73 74 |
# File 'lib/tcontroller.rb', line 72 def closecircuit (circnum) errorstate,ans=sr(:closecircuit," #{circnum}") end |
#ds ⇒ Object
Returns the an array of of directory servers from the consensus.
Tor::TController.ds => [w.x.y.z:port, …]
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/tcontroller.rb', line 95 def ds reply=[] s = getinfo("ns/all") case version when /0.2.[01]/ z=2 when/0.2.2/ z = 4 # To accommodate r, s , w and p] end s.collect!{|eachs| eachs.start_with?("r ") ? eachs : nil } s.delete nil s.each{|eachs| dsport=eachs.split[8].to_i rip=eachs.split[6] reply << "#{rip}:#{dsport}" if dsport!= 0 } reply end |
#extendcir(circnum, or_list) ⇒ Object
Creating a new circuit
create_circ = Tor::TController.extendcir(0,['or1','or2','or3'])
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/tcontroller.rb', line 120 def extendcir(circnum,or_list) argor=" #{circnum} #{or_list.join(',')}" extendcir=send_command(:extendcircuit,argor) circuit_id=nil readterm=true while readterm do case msg=read_reply when /^\d+ CIRC \d+ BUILT/,/250 / #/^\d+ CIRC \d+ BUILT/ circuit_id=msg.scan(/\d+\Z/)[0] readterm=false when /^5\d\d / readterm=false when /^\d+ / puts msg #like extended launched else puts msg,"\n" end end #sr(:signal,"newnym") circuit_id end |
#extendcir_slowly(orarray) ⇒ Object
This builds a circuit to each member of the array argument, skipping any node that fails to connect.
It returns the circuit number, and the longest successful circuit that was successfully built.
There is a delay of 2.0 seconds after each extension, but this can be altered by defining Tor::EXTEND_DELAY constant.
<b>Create a circuit as long as possible using 10 elements in an array</b>
testarray = [A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z]
Tor::TController.extendcir_slowly(testarray)
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/tcontroller.rb', line 149 def extendcir_slowly(orarray) ordelay = defined?(EXTEND_DELAY) ? EXTEND_DELAY : Constants::EXTEND_DELAY cirnum = 0 circuit = [] orarray.each{|eachor| cirnum=extendcir(cirnum,[eachor]) sleep(ordelay) # wait for a few seconds, and check if the circuit is was successful p=cir_status.detect{|i| i =~ (/^#{cirnum} / )} case p when /FAILED/,nil puts "cirnum=nil" if eachor != circuit.last cirnum = extendcir(0,circuit) sleep(circuit.count) elsif circuit.empty? return nil # failed to build circuit at start, make sure orarray[0] is up end when /EXTENDED/, /BUILT/ circuit << eachor puts "Extended! cirnum = #{cirnum}, circuit length = #{circuit.count}" when /LAUNCHED/ sleep(1) puts x=cir_status.detect{|a| a =~ /^#{cirnum}/} circuit << eachor if (x =~ /BUILT/) or (x =~/EXTENDED/) end } [cirnum,circuit] end |
#get_bridges(cacheddesc, *config) ⇒ Object
Tor::TController.get_bridges( Tor::TController.:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0.0:proxytype=>‘tor’,:proxyport=>9050,:proxyaddr=>‘127.0.0.1’ )
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/tcontroller.rb', line 187 def get_bridges(cacheddesc, *config) url = URI.parse "https://bridges.torproject.org/" if config.empty? proxyconfig={:type=>'tor' ,:port=>9050,:addr=>'127.0.0.1'} else proxyconfig = config[0] end if ! defined?(@myhttperrors) @myhttperrors=0 end case proxyconfig[:type] when /none/i,nil http_session=Net::HTTP.new(url.host,url.port) when /socks/i,/tor/i http_session=Net::HTTP.SOCKSProxy(proxyconfig[:addr], proxyconfig[:port]).new(url.host,url.port) when /http/i,/https/i,/polipo/i http_session=Net::HTTP::Proxy(proxyconfig[:addr], proxyconfig[:port]).new(url.host,url.port) end if url.scheme=="https" http_session.use_ssl = true http_session.verify_mode = OpenSSL::SSL::VERIFY_NONE else http_session.use_ssl=false end bridges=[] # Rescue from http error begin resp = http_session.get2 url.path # Let Tor choose circuit itself # Additional code will be added shortly to attach the stream to the circuit directly puts "#{resp.code} HTTP response" #puts resp.body respcode= resp.code=="200" ? 200:nil if resp.code == "200" torbridgeip=resp.body.scan(/\d+\.\d+\.\d+\.\d+\:\d+/) torbridgeip.each{|eachbridge| bridgeip,bridgeport= eachbridge.split(':') x=Bridge.where(:ipaddr=>bridgeip, :port =>bridgeport) if x.empty? if cacheddesc.nil? or (bridge_geoip=cacheddesc.get_geoiprecord(bridgeip)).nil? Bridge.create(:ipaddr=>bridgeip, :port =>bridgeport, :lat=>0, :lng=>0) else Bridge.create(:ipaddr=>bridgeip, :port =>bridgeport, :lat=>bridge_geoip.latitude.to_f, :lng=>bridge_geoip.longitude.to_f ) end end } end bridges = torbridgeip rescue @myhttperrors +=1 respcode=nil bridges=[] end bridges.nil? ? [] : bridges #Return array of all bridges end |
#get_entryguards ⇒ Object
Get entry-guards
Tor::TController.get_entryguards #=> ["$abc123","$def456"...]
282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/tcontroller.rb', line 282 def get_entryguards rslt = getinfo "entry-guards" reply = rslt.collect{|eachguard| case eachguard when / unusable/ nil else "$"+ eachguard.split(/[~ =]/)[0] end } reply.delete(nil) reply end |
#get_httperrors ⇒ Object
298 299 300 |
# File 'lib/tcontroller.rb', line 298 def get_httperrors @myhttperrors end |
#get_purposeip(nodetype) ⇒ Object
This gets the IP addresses for ORs based on the characteristics of the OR.
Example of the properties include: _Fast_, _Guard_, _HSDir_, _Named_, _Running_, _Stable_, _V2Dir_, _Valid_, _Exit_.
<b>Get all Exit, Fast and entry Guard ORs</b>
Tor::TController.get_purposeip("Exit") #=> ["a.b.c.d","e.f.g.h"...]
Tor::TController.get_purposeip("fast exit")
Tor::TController.get_purposeip("Guard")
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/tcontroller.rb', line 310 def get_purposeip(nodetype) reply=[] s = getinfo("ns/all") ctr_i= s.size / 2 ctr_i.times{|j| rip=s[j*2].split[6] x=Router.where(:ipaddr=>rip) if !x.empty? finprint = "$" + x[0].fingerprint matcharray=nodetype.split.collect{|eachtype| if eachtype.start_with? '!' matchme = eachtype[1..(eachtype.length-1)] rslt = !(s[j*2+1] =~ (/#{matchme}/i)) rslt ? rslt : nil #return nil if false, or return the number else s[j*2+1] =~ (/#{eachtype}/i) end } reply << finprint if !matcharray.include? nil end } reply end |
#getconf(confname) ⇒ Object
For more details, see [gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt]
342 343 344 345 346 347 348 349 350 351 |
# File 'lib/tcontroller.rb', line 342 def getconf(confname) send_command(:getconf, confname) reply=[] case msg=read_reply when /250 / msg.split(/250 \S*=/).last else msg end end |
#getinfo(*args) ⇒ Object
This method sends the “GETINFO” protocol message with the arguments.
<b>Getting more information from Tor</b>
Tor::TController.getinfo("ns/all")
359 360 361 362 |
# File 'lib/tcontroller.rb', line 359 def getinfo(*args) errorcode,ans = sr(:getinfo,*args) ans end |
#net_status ⇒ Object
This returns an array of hash tables with the fingerprints of all onion routers that have not been marked as down.
<b>Get the network status from Tor</b>
Tor::TController.net_status => [ {:fingerprint=>"$ABCD"},{:fingerprint=>"$EFGH"}...]
369 370 371 372 373 374 375 376 |
# File 'lib/tcontroller.rb', line 369 def net_status case version when /0.2.[01]/ net_status1 when/0.2.2/ net_status2 end end |
#newstreams ⇒ Object
This returns all the new streams that have not been assigned to a circuit
253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/tcontroller.rb', line 253 def newstreams reply=[] getinfo("stream-status").each{|eachstream| case eachstream when /\d+ NEW 0/ # It might be simpler to use this /\d+ NEW/ reply << eachstream.scan(/\d+/)[0].to_i end } reply end |
#setconf(confname, value) ⇒ Object
Tor::TController.setconf(“__DisablePredictedCircuits”,1) =>[“OK”, []]
Tor::TController.setconf("__LeaveStreamsUnattached",1) =>["OK", []]
Tor::TController.setconf("ORPort",9001) =>["OK", []]
429 430 431 |
# File 'lib/tcontroller.rb', line 429 def setconf(confname,value) sr(:setconf,"#{confname}=#{value}") end |
#signal(args) ⇒ Object
This method sends “signals” protocol message with the arguments.
<b>Reload Tor config from file</b>
Tor::TController.signal(“RELOAD”) Tor::TController.signal(“HUP”)
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/tcontroller.rb', line 439 def signal(args) reply=[] case (args) when /NEWNYM/i,/CLEARDNSCACHE/i,/RELOAD/i,/HUP/i,/DUMP/i,/USR1/i,/DEBUG/i,/USR2/i,/shutdown/i,/INT/i errorcode,reply=sr(:signal, args) close if args =~ /shutdown/i or args =~ /INT/i when /HALT/i,/TERM/i send_command(:signal, "HALT") close else puts "#{args} not recognised by the at library development. Sending the signal nonetheless" reply=sr(:signal,args) end reply end |
#sr(command, *args) ⇒ Object
This sends commands and returns the protocol response code along with an array
containing the results with the following format \[errorcode,\[array_of_results]].
<b>Send and receive commands</b>.
Tor::TController.sr(:signal,"reload")
Tor::TController.sr(:signal,"newnym")
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/tcontroller.rb', line 462 def sr(command, *args) send_command(command, *args) reply=[] readterm=true while readterm do # Read as much as possible until '250 OK' or error 5YZ case msg=read_reply when /^250 OK/ readterm=false puts errorstate="OK" when /^250[\+,\-,\s]/ reply << msg.split(/^\d+[\+,\-,\s]\S*=/).last unless msg=~/250\+/ errorstate = "OK" when /^\./ when /^5\d\d / if errorstate == "OK" # if a "2yz " code came before this then msg is part of response reply << msg else puts msg errorstate = msg.match(/^5\d\d/) readterm=false end else reply << msg end end reply.delete(nil) reply = errorstate=="OK" ? reply : [] [errorstate,reply] end |