[tor-commits] [stem/master] Tutorial for custom circuits
atagar at torproject.org
atagar at torproject.org
Sat May 23 23:05:37 UTC 2015
commit 80d692d68795d6e1f04e1c3246d66c0db1b8eee9
Author: Damian Johnson <atagar at torproject.org>
Date: Sat May 23 15:59:42 2015 -0700
Tutorial for custom circuits
Yay for two birds with one stone! For years I've wanted to expand our tutorial
with an example of manual circuit construction...
https://trac.torproject.org/projects/tor/ticket/8728
Roger asked me for a simple demo of bandwidth scanning, which is a perfect fit!
---
docs/tutorials/to_russia_with_love.rst | 132 +++++++++++++++++++++++++++++++-
1 file changed, 130 insertions(+), 2 deletions(-)
diff --git a/docs/tutorials/to_russia_with_love.rst b/docs/tutorials/to_russia_with_love.rst
index 8a709f5..f8bedc6 100644
--- a/docs/tutorials/to_russia_with_love.rst
+++ b/docs/tutorials/to_russia_with_love.rst
@@ -4,6 +4,7 @@ To Russia With Love
* :ref:`using-pycurl`
* :ref:`using-socksipy`
* :ref:`reading-twitter`
+* :ref:`custom-path-selection`
.. _using-pycurl:
@@ -153,8 +154,8 @@ with...
Reading Twitter
---------------
-Now lets do somthing a little more interesting, and read a Twitter feed over
-Tor. This can be done `using thier API
+Now lets do something a little more interesting, and read a Twitter feed over
+Tor. This can be done `using their API
<https://dev.twitter.com/rest/reference/get/statuses/user_timeline>`_, for
authentication `see their instructions
<https://dev.twitter.com/oauth/overview/application-owner-access-tokens>`_...
@@ -251,3 +252,130 @@ authentication `see their instructions
.. image:: /_static/twitter_output.png
+.. _custom-path-selection:
+
+Custom Path Selection
+---------------------
+
+Routing requests over Tor is all well and good, but what if you want to do
+something more sophisticated? Through Tor's controller interface you can manage
+your own **circuits** and **streams**.
+
+A **circuit** is your path through the Tor network. Circuits must consist of at
+least two relays, and must end with a relay that allows connections to the
+destination you want to reach.
+
+**Streams** by contrast are TCP connections carried over a circuit. Tor handles
+attaching streams to a circuit that can service it. To instead manage this
+yourself call...
+
+::
+
+ controller.set_conf('__LeaveStreamsUnattached', '1')
+
+For an example of this lets fetch a site over each relay to determine it's
+reachability and speed. **Naturally doing this causes quite a bit of load so
+please be careful not to leave this running!**
+
+::
+
+ import StringIO
+ import time
+
+ import pycurl
+
+ import stem.control
+
+ # Static exit for us to make 2-hop circuits through. Picking aurora, a
+ # particularly beefy one...
+ #
+ # https://atlas.torproject.org/#details/379FB450010D17078B3766C2273303C358C3A442
+
+ EXIT_FINGERPRINT = '379FB450010D17078B3766C2273303C358C3A442'
+
+ SOCKS_PORT = 9050
+ CONNECTION_TIMEOUT = 30 # timeout before we give up on a circuit
+
+ def query(url):
+ """
+ Uses pycurl to fetch a site using the proxy on the SOCKS_PORT.
+ """
+
+ output = StringIO.StringIO()
+
+ query = pycurl.Curl()
+ query.setopt(pycurl.URL, url)
+ query.setopt(pycurl.PROXY, 'localhost')
+ query.setopt(pycurl.PROXYPORT, SOCKS_PORT)
+ query.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME)
+ query.setopt(pycurl.CONNECTTIMEOUT, CONNECTION_TIMEOUT)
+ query.setopt(pycurl.WRITEFUNCTION, output.write)
+
+ try:
+ query.perform()
+ return output.getvalue()
+ except pycurl.error as exc:
+ raise ValueError("Unable to reach %s (%s)" % (url, exc))
+
+
+ def scan(controller, path):
+ """
+ Fetch check.torproject.org through the given path of relays, providing back
+ the time it took.
+ """
+
+ 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
+ start_time = time.time()
+
+ check_page = query('https://check.torproject.org/')
+
+ if 'Congratulations. This browser is configured to use Tor.' not in check_page:
+ raise ValueError("Request didn't have the right content")
+
+ return time.time() - start_time
+ finally:
+ controller.remove_event_listener(attach_stream)
+ controller.reset_conf('__LeaveStreamsUnattached')
+
+
+ with stem.control.Controller.from_port() as controller:
+ controller.authenticate()
+
+ relay_fingerprints = [desc.fingerprint for desc in controller.get_network_statuses()]
+
+ for fingerprint in relay_fingerprints:
+ try:
+ time_taken = scan(controller, [fingerprint, EXIT_FINGERPRINT])
+ print '%s => %0.2f seconds' % (fingerprint, time_taken)
+ except Exception as exc:
+ print '%s => %s' % (fingerprint, exc)
+
+::
+
+ % python scan_network.py
+ 000050888CF58A50E824E534063FF71A762CB227 => 2.62 seconds
+ 000149E6EF7102AACA9690D6E8DD2932124B94AB => 2.50 seconds
+ 000A10D43011EA4928A35F610405F92B4433B4DC => 2.18 seconds
+ 000F18AC2CDAE4C710BA0898DC9E21E72E0117D8 => 2.40 seconds
+ 0011BD2485AD45D984EC4159C88FC066E5E3300E => 2.03 seconds
+ 003000C32D9E16FCCAEFD89336467C01E16FB00D => 11.41 seconds
+ 008E9B9D7FF523CE1C5026B480E0127E64FA7A19 => 2.24 seconds
+ 009851DF933754B00DDE876FCE4088CE1B4940C1 => 2.39 seconds
+ 0098C475875ABC4AA864738B1D1079F711C38287 => Unable to reach https://check.torproject.org/ ((28, 'SSL connection timeout'))
+ 00B70D1F261EBF4576D06CE0DA69E1F700598239 => 2.41 seconds
+ 00DFA1137D178EE012B96F64D12F03B4D69CA0B2 => 4.53 seconds
+ 00EF4569C8E4E165286DE6D293DCCE1BB1F280F7 => Circuit failed to be created: CHANNEL_CLOSED
+ 00F12AB035D62C919A1F37C2A67144F17ACC9E75 => 3.58 seconds
+ 00F2D93EBAF2F51D6EE4DCB0F37D91D72F824B16 => 2.12 seconds
+ 00FCFBC5770DC6B716D917C73A0DE722CCF2DFE5 => 2.16 seconds
+ ...
+
More information about the tor-commits
mailing list