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?

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))
  • I see, but is there a way to see which of the many BUILT circuits is the one that will be used by default? When you tunnel traffic through the SOCKS5 port, which circuit will be used when there are say, 5 available? – Alen Browin Jun 19 '15 at 21:51
  • yeah you can list the circuits, path, and their build status. stem.torproject.org/tutorials/examples/list_circuits.html – Lizbeth Jun 21 '15 at 15:48
  • But when I do that there are multiple circuits which have the BUILD status, that is why I posted here at all. No way to tell which of the circuits is going to be used in the next TCP stream. – Alen Browin Jun 21 '15 at 21:15
  • They're selected at random from those pre-built circuits. That's why I showed you how to control your own circuits instead of relying on the built-in random process. – Lizbeth Jun 22 '15 at 20:46
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.