This is a single (sub-)circuit object over exactly 3 nodes.Suitable nodes must be chosesn to allow the creation of a successful circuit.
Initialises a Tor::Circuit instance variable with attibutes including the @built, @cirnum and @torcontroller Use nil for proxyport if Tor is running already.
# File lib/circuits.rb, line 8 def initialize(ctrller_config, circuitarray, proxyconfig) @built = true @closed = true @circuitarray = circuitarray @cirnum = nil @ctrller_config = ctrller_config @proxyconfig = proxyconfig if @proxyconfig.nil? # When proxyconfig.nil?, then it's an existing @launched = true @torcontroller = Tor::TController.new(@ctrller_config) else @launched = false end end
This tries to attach all streams to the circuit.
# File lib/circuits.rb, line 164 def attach_streams controller.newstreams.each{|z| controller.attach_stream(z,@cirnum) } end
This methods checks if the circuit has been built. It only reflects a single segment of the circuit
# File lib/circuits.rb, line 76 def built? if defined?(@torcontroller) # cant check built? before launching. @built = ! @torcontroller.cir_status.detect{|z| z =~ /#{@cirnum} BUILT/ }.nil? if not @cirnum.nil? else false end end
Returns the nodes that make up the circuit.
# File lib/circuits.rb, line 24 def circuit @circuitarray end
Returns the circuit number. Returns 0 if it has not been attached
# File lib/circuits.rb, line 36 def cirnum @cirnum end
Closes the Tor and Polipo launched by the instance of this class, and removes the tmp directory
# File lib/circuits.rb, line 152 def close_apps if defined?(@pid) @torcontroller.signal("SHUTDOWN") Process.kill("KILL",@pid[:polipo]) FileUtils.remove_entry_secure @path # srm path ( delete tmp directory recursively ) @launched=false @built=false end @closed = true end
Closes the circuit
# File lib/circuits.rb, line 146 def closecir @torcontroller.closecircuit(@cirnum) if ! @cirnum.nil? @built=false end
Checks if the application instances for Tor and polipo have been closed
# File lib/circuits.rb, line 41 def closed? @closed end
Returns the Tor:Controller used for the circuit.
# File lib/circuits.rb, line 29 def controller if defined?(@torcontroller) @torcontroller end end
This creates / builds the actual circuit using @circuitarray.
# File lib/circuits.rb, line 46 def extend if defined?(@torcontroller) @cirnum = @torcontroller.extendcir(0,@circuitarray) else puts "launch before extending\n" return nil end end
This gets 3 bridge IP addresses from the Tor bridge website. proxyconfig is optional. default proxyconfig = {:type=>‘polipo’ ,:port=>8118,:addr=>‘127.0.0.1’} The return format is fo the form:
[HTTPcode, [{:bridgeip, :bridgeport},{:bridgeip, :bridgeport},{:bridgeip, :bridgeport}]. The types can be one of ‘tor’, ‘polipo’, ‘socks’, ‘http’, ‘https’,nil, ‘none’.
Get 3 bridges
Tor::Circuit.get_bridges( Tor::Cacheddesc, {:proxytype=>'polipo',:proxyport=>8118,:proxyaddr=>'127.0.0.1'} )
cachedDesc can be nil if the Google Earth file is not needed.
# File lib/circuits.rb, line 181 def get_bridges(cacheddesc, *config) url = URI.parse "https://bridges.torproject.org/" if config.empty? proxyconfig={:type=>'polipo' ,:port=>8118,:addr=>'127.0.0.1'} else proxyconfig = config[0] end if ! defined?(@myhttperrors) @myhttperrors=0 end case proxyconfig[:type] when /none/,nil http_session=Net::HTTP.new(url.host,url.port) when /socks/,/tor/ http_session=Net::HTTP.SOCKSProxy(proxyconfig[:addr], proxyconfig[:port]).new(url.host,url.port) when /http/,/https/,/polipo/ 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 = Tor::Bridge.where(:ipaddr=>bridgeip, :port =>bridgeport) if x.empty? if cacheddesc.nil? or (bridge_geoip = cacheddesc.get_geoiprecord(bridgeip)).nil? Tor::Bridge.create(:ipaddr=>bridgeip, :port =>bridgeport, :lat=>0, :lng=>0) else Tor::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
Run this after initializing a Tor::Circuit instaance. This writes the following Tor configuration options to a temp file if proxyport not nil: Write HttpProxy, HttpsProxy , DataDirectory /tmp/dir, __LeaveStreamUnattached 1. This also writes polipoo configuration to a temporary file and executes polipo It executes Tor and polipo if proxyport is not nil Note: The applicaitons will continue running even if the ruby shell is exited. The #close_apps method can be used to terminate the application and remove the temp dir
# File lib/circuits.rb, line 93 def launch # should I use popen3? dont need stdin and stderror from tor or polipo if ! @proxyconfig.nil? @path = Dir.mktmpdir if not defined?(@path) @pid= {} torrc_filename = File.join(@path,"torrc") torrc = File.new( torrc_filename, "w") # populate torrc socks_port = @ctrller_config[:port] - 1 torrc.puts "ControlPort #{@ctrller_config[:port]}\n" torrc.puts "DataDirectory #{@path}\n" torrc.puts "HttpProxy 127.0.0.1:#{@proxyconfig - 1}\n" # Use the preceeding polipo port torrc.puts "HttpsProxy 127.0.0.1:#{@proxyconfig - 1}\n" torrc.puts "RunAsDaemon 1\n" torrc.puts "SocksPort #{socks_port}\n" torrc.puts "SocksListenAddress 127.0.0.1\n" # can add a random password and call tor --hashcontrolpassword read stdout..but feels like long thing. Or ruby implementation of hash torrc.close puts "Torrc config written \n" #puts @tor_io=Process.spawn("tor","-f",torrc_filename) # stdin, stdout, stderr, thread #puts @tor_io=Open3.popen3("tor","-f",torrc_filename) # stdin, stdout, stderr, thread @pid[:tor] = Process.spawn("tor","-f",torrc_filename) sleep(7) # wait 7 seconds to download cached consensus and descriptors. -Consider copuing the existing one from the previous directory # check here # **************** why sleep? can I use the cached desc from the first tor process @torcontroller = Tor::TController.new(@ctrller_config) # write proxyconfig to polipo polipo_filename = File.join(@path,"polipo_config") polipo_config = File.new( polipo_filename , "w") polipo_config.puts "proxyPort = #{@proxyconfig}\n" polipo_config.puts "socksParentProxy = localhost:#{socks_port}\n" polipo_config.puts "socksProxyType = socks5\n" polipo_config.puts "daemonise = true\n" polipo_log = File.join(@path,"polipo_log") polipo_pid = File.join(@path,"polipo.pid") polipo_forbid = File.join(@path,"forbidden") polipo_config.puts "logFile = #{polipo_log}\n" polipo_config.puts "pidFile = #{polipo_pid}\n" polipo_config.puts "forbiddenFile = #{polipo_forbid}\n" polipo_config.close @pid[:polipo]= Process.spawn( "polipo", "-c", polipo_filename) end @torcontroller = Tor::TController.new(@ctrller_config) # @path = @torcontroller.getconf("DataDirectory") when proxyconfig==nil # dont need path for the first Tor @torcontroller.setconf("__DisablePredictedCircuits",1) @torcontroller.setconf("newcircuitperiod",999999999) @torcontroller.setconf("maxcircuitdirtiness",999999999) @torcontroller.setconf("MaxOnionsPending",0) @torcontroller.setconf("__LeaveStreamsUnattached",1) @launched = true @closed = false end
Checks if the launched method has been called
# File lib/circuits.rb, line 85 def launched? @launched end
This attaches all streams on this controller to a prebuilt circuit that has been
# File lib/circuits.rb, line 56 def start if ! launched? launch end if ! built? extend end # sleep(3.5) ###################### wait 3 seconds before checking if built. # May not be needed # use events here instead to (build) no matter what. or (launch and build). If built, attach existing streams from preceeding subcircuit if built? streams_array = @torcontroller.newstreams if ! streams_array.empty? and ! @cirnum.nil? streams_array.each{|each_stream| @torcontroller.attach_stream(each_stream, @cirnum) } end end end