3

I am able to list the circuits, but for some reason I'm never able to quite get a circuit alone consistently, there always appears to be many of them with state BUILT. This is especially true after I close_circuit() on everything, Tor seems to automatically build anywhere from 1 to 5 at random right after.

The only way to figure out which is in use is to get IP from a website and match it against all available exit nodes.

Is there a way to either force Tor to only ever maintain a single circuit or to somehow figure out which circuit is actually being used on the SOCKS5 port?

Jens Kubieziel
  • 8,630
  • 5
  • 35
  • 116
Alen Browin
  • 43
  • 1
  • 4

2 Answers2

3

I put this example together using this STEM Tutorial. It shows the use of

controller.set_conf('__LeaveStreamsUnattached', '1')

to make your own circuits, attach a stream, and make a request using the requesocks module (which is just the requests module with SOCKS5 support). Hope this helps.

import StringIO
import time

import stem.control
import requesocks
import random

EXIT_FINGERPRINT = '379FB450010D17078B3766C2273303C358C3A442'

SOCKS_PORT = 9150
CONTROL_PORT = 9151
CONNECTION_TIMEOUT = 30  # timeout before we give up on a circuit

def get(url):
  """
  Uses pycurl to fetch a site using the proxy on the SOCKS_PORT.
  """
  session = requesocks.session()
  session.proxies = {
    'http': 'socks5://127.0.0.1:%s' % SOCKS_PORT,
    'https': 'socks5://127.0.0.1:%s' % SOCKS_PORT,
  }
  try: 
    response = session.get(url)
    return response
  except:
    print("Could not connect")

def connect(controller, path, url):
  """ Build a custom 2 hop circuit using the path fingerprint
  and the hard coded exit node """

  circuit_id = controller.new_circuit(path, await_build = True)

  def attach_stream(stream):
    if stream.status == 'NEW':
      controller.attach_stream(stream.id, circuit_id)

  controller.add_event_listener(attach_stream, stem.control.EventType.STREAM)

  try:
    controller.set_conf('__LeaveStreamsUnattached', '1')  # leave stream management to us
    check_page = get(url)
    return check_page
  finally:
    # Stop listening for attach stream events and stop controlling streams
    controller.remove_event_listener(attach_stream)
    controller.reset_conf('__LeaveStreamsUnattached')

with stem.control.Controller.from_port(port=CONTROL_PORT) as controller:
  controller.authenticate()

  relay_fingerprints = [desc.fingerprint for desc in controller.get_network_statuses()]

  fingerprint = random.choice(relay_fingerprints)
  try:
    url = "http://www.torproject.org"
    response = connect(controller, [fingerprint, EXIT_FINGERPRINT], url)
    if response.status_code == 200:
        print("Connection to %s successful using node %s" % (url, fingerprint))
  except Exception as exc:
      print('%s => %s' % (fingerprint, exc))
Lizbeth
  • 1,274
  • 6
  • 22
2

To force an application to use a particular circuit your best option is to handle attaching streams to circuits yourself. For an example of this see its tutorial. Usually you'll leave __LeaveStreamsUnattached set, and have all new stream events bind it to the circuit you're after.

Damian
  • 681
  • 3
  • 2