Doing an operation for all exits with a certain characteristic is a reasonably common task, for instance to check relay speeds or look for malicious exits.
'Check for ssl strip on all Russian exits' would be a natural extension of our client usage tutorial, and would exhibit quite a bit of controller functionality none of the other tutorials do at present.
This would involve three steps...
Write a script that we will use for the tutorial example.
Hi ragwater, sorry about the delay. This script looks great! Feedback below...
from stem.util import term
The first example already demos the term util and printing bootstrap messages. Dropping this from later examples simplifies the scripts and makes them more focused on just what we're trying to show. I did this for another recent addition...
Running 'pep8 --ignore E251,E501,E111,E127' over your script will highlight these issues. For an explanation of the parts of pep8 that we're ignoring see...
Though as mentioned above we should probably drop init_msg_handler, so guess there's no point in having this span multiple lines.
total=sum(value for value in data.values())
Another pep8 thing but the '=' should have a space on either side of it.
# I was considering checking allowed ports (443) at this point by# getting microdescriptors for each node, we can either filter it here# or wait for it to happen at getting response stage (it will FAIL then).node_gen = controller.get_network_statuses()filtered_nodes = filter_nodes(controller, node_gen) # [-20:]circ_waiting_list = Queue.Queue()
Good idea about filtering based on the exit policy. Lets do this via server descriptors since microdescriptors make this a real pita. If you add "FetchUselessDescriptors 1" to the config then this should do the trick...
from stem.control import Controllerwith Controller.from_port(port = 9051) as controller: controller.authenticate() russian_exits = [] for desc in controller.get_server_descriptors(): if desc.exit_policy.can_exit_to(port = 443): # check if this exit is in russia exit_locale = controller.get_info('ip-to-country/%s' % desc.address) if exit_locale == 'ru': russian_exits.append(desc) print "Russian Exits:" for desc in russian_exits: print " %s (%s)" % (desc.nickname, desc.address)
There's actually no need to honour the 'Exit' flag. That is just an indicator from the directory authorities that a relay allows certain ports and is relatively quick. Lacking the flag doesn't necessarily mean that a relay can't serve as an exit (that's determined by its exit policy).
One gotcha though - there doesn't appear to be any Russian exits. sigh
$ python example.py Russian Exits:
For testing lets use another locale, then we'll note in the tutorial that they might need to pick someplace else.
Anyhow passing
strict = True
along (or specifying the address) with desired port solves the issue and gives us a healthy number of exit nodes.
from stem import StreamStatus
I have no idea how I've managed to miss it, thanks for the catch.
I'm yet unsure how to get the cert checking in urllib with socks but I should figure it out in a few days' time and deliver the code, pep8-approved this time around ;).
Should the info text showcasing the stream events go as well?
That's definitely an interesting idea, but lets initially keep the example simple initially. Maybe just printing the exits as we use them (with a message if we encounter an issue).
Turns out exit_policy.can_exit_to() responds in an interesting manner when only the port parameter is provided, and when I run your script against the US locale, it returned ~10 exit nodes, none of them being really usable as far as I can tell
Oops, I should have included the strict flag. Those relays are being returned because they do allow exiting on port 443... but only for one IP.
Originally 'strict' was the default so it would only match if the relay accepted all 443 traffic but some users found that unintuitive.
Anyhow passing strict = True along (or specifying the address) with desired port solves the issue and gives us a healthy number of exit nodes.
Glad to hear! When you provide an IP address the 'strict' flag doesn't do anything. As the pydocs mention that only effects how an undefined address or port is handled.
I'm yet unsure how to get the cert checking in urllib with socks but I should figure it out in a few days' time and deliver the code, pep8-approved this time around ;).
As talked on IRC it might be a good idea to split 'sslstrip' up into two seperated scripts:
a) use SETCONF (ExitNodes and StrictExitNodes) and NEWNYM signal to let Tor build a new circuit (path length might be even shortened to 2).
b) manually circuit construction with rotating exit and fixed guard node for use as an example