commit 4a6b164cbefb5dca519ece6cfd62486c8a14206e Author: Isis Lovecruft isis@torproject.org Date: Thu Sep 20 03:38:29 2012 +0000
* Moving to using @defer.inlineCallbacks for rewriting the torrc Bridge line. NOT DONE YET. NOT TESTED YET. * Moving to bridges being assets and relays being a list attached to our TorState() instance, so that we can pass it to CustomCircuit. TODO: Make the CustomCircuit() instance handle iteration through relay list, and provide access to objects for unreachable and reachable relays. We should probably check how onionoo handles this. --- ooni/plugins/bridget.py | 134 +++++++++++++++++++++++++++++++---------------- ooni/utils/circuit.py | 18 +++--- 2 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/ooni/plugins/bridget.py b/ooni/plugins/bridget.py index 192c2dd..07d7269 100644 --- a/ooni/plugins/bridget.py +++ b/ooni/plugins/bridget.py @@ -341,55 +341,91 @@ class BridgetTest(OONITest): rmtree(temp, ignore_errors=True)
#@timer(self.circuit_timeout) + @defer.inlineCallbacks def reconfigure_bridge(state, bridge, use_pt=False, pt_type=None): - """Rewrite the Bridge line in our torrc.""" - log.msg("Current Bridge: %s" % bridge) - if use_pt is False: - state.protocol.set_conf('Bridge', bridge) - elif use_pt and pt_type is not None: - state.protocol.set_conf('Bridge', pt_type +' '+ bridge) - else: - raise PTNotFoundException - return state.callback + """ + Rewrite the Bridge line in our torrc. If use of pluggable + transports was specified, rewrite the line as: + Bridge <transport_type> <ip>:<orport> + Otherwise, rewrite in the standard form. + """ + log.msg("Current Bridge: %s" % bridge) + try: + if use_pt is False: + reset_tor = yield state.protocol.set_conf('Bridge', bridge) + elif use_pt and pt_type is not None: + reset_tor = yield state.protocol.set_conf('Bridge', + pt_type +' '+ bridge) + else: + raise PTNotFoundException + + controller_response = reset_tor.callback + if not controller_response: + defer.returnValue((state.callback, None)) + else: + defer.returnValue((state.callback, controller_response)) + except Exception, e: + log.msg("Reconfiguring torrc Bridge line failed with %s" % bridge)
def reconfigure_fail(*param): log.msg("Reconfiguring TorConfig with parameters %s failed" % param) reactor.stop()
- def remove_relays(state, bridge_list): + @defer.inlineCallbacks + def remove_public_relays(state, bridges): """ Remove bridges from our bridge list which are also listed as public relays. """ - ips = map(lambda addr: addr.split(':',1)[0], bridge_list) - both = set(state.relays.values()).intersection(ips) - if len(both) > 0: - for bridge in both: - bridge_list.remove(bridge) - return state.callback + IPs = map(lambda addr: addr.split(':',1)[0], bridges) + both = set(state.routers.values()).intersection(IPs)
- def remove_relays_fail(state): - log.msg("Unable to remove public relays from the bridge list.") + def __remove_line__(node, bridges=bridges): + for line in bridges: + if line.startswith(node): + log.msg("Removing %s because it is a public relay" % node) + bridges.remove(line)
- def setup_fail(args): - log.msg("Setup Failed.") - report.update({'failed': args}) + if len(both) > 0: + try: + updated = yield map(lambda node: __remove_line__(node), both) + if not updated: + ## XXX do these need to be state.callback? + defer.returnValue(state) + else: + defer.returnValue(state) + except Exception, e: + log.msg("Unable to remove public relays from bridge list:\n%s" + % both) + log.err(e) + + def setup_fail(proto, bridge_list, relay_list): + log.err("Setup Failed: %s" % proto) + log.err("We were given bridge list:\n%s\nAnd our relay list:\n%s\n" + % (bridge_list, relay_list)) + report.update({'setup_fail': 'FAILED', + 'proto': proto, + 'bridge_list': bridge_list, + 'relay_list': relay_list}) reactor.stop()
- def setup_done(proto): + def setup_done(proto, bridge_list, relay_list): log.msg("Setup Complete: %s" % proto) state = TorState(proto.tor_protocol) state.post_bootstrap.addCallback(state_complete).addErrback(setup_fail) - report.update({'success': args}) - - def start_tor(reactor, update, torrc, to_delete, control_port, - tor_binary, data_directory): + if bridge_list is not None: + state.post_bootstrap.addCallback(remove_public_relays, bridge_list) + if relay_list is not None: + raise NotImplemented + #report.update({'success': args}) + + def start_tor(reactor, update, torrc, to_delete, control_port, tor_binary, + data_directory, bridge_list=None, relay_list=None): """ Create a TCP4ClientEndpoint at our control_port, and connect it to our reactor and a spawned Tor process. Compare with :meth:`txtorcon.launch_tor` for differences. """ - ## XXX do we need self.reactor? end_point = TCP4ClientEndpoint(reactor, 'localhost', control_port) connection_creator = partial(end_point.connect, TorProtocolFactory()) process_protocol = TorProcessProtocol(connection_creator, updates) @@ -406,9 +442,9 @@ class BridgetTest(OONITest): except RuntimeError, e: process_protocol.connected_cb.errback(e) finally: - return process_protocol.connected_cb + return process_protocol.connected_cb, bridge_list, relay_list
- def state_complete(state): + def state_complete(state, bridge_list=None, relay_list=None): """Called when we've got a TorState.""" log.msg("We've completely booted up a Tor version %s at PID %d" % (state.protocol.version, state.tor_pid)) @@ -418,7 +454,12 @@ class BridgetTest(OONITest): for circ in state.circuits.values(): log.msg("%s" % circ)
- return state + if bridge_list is not None and relay_list is None: + return state, bridge_list + elif bridge_list is None and relay_list is not None: + raise NotImplemented + else: + return state, None
def state_attach(state, relay_list): log.msg("Setting up custom circuit builder...") @@ -426,12 +467,12 @@ class BridgetTest(OONITest): state.set_attacher(attacher, reactor) state.add_circuit_listener(attacher)
- for circ in state.circuits.values(): - for relay in circ.path: - try: - relay_list.remove(relay) - except KeyError: - continue + #for circ in state.circuits.values(): + # for relay in circ.path: + # try: + # relay_list.remove(relay) + # except KeyError: + # continue ## XXX how do we attach to circuits with bridges? d = defer.Deferred() attacher.request_circuit_build(d) @@ -457,7 +498,6 @@ class BridgetTest(OONITest): data_dir = mkdtemp(prefix='bridget-tordata') delete_list.append(data_dir) conf.DataDirectory = data_dir - #conf.__OwningControllerProcess = os.getpid()
(fd, torrc) = mkstemp(dir=data_dir) delete_list.append(torrc) @@ -468,8 +508,16 @@ class BridgetTest(OONITest):
log.msg("Bridget: initiating test ... ")
- while self.bridges_remaining() > 0: - self.current_bridge = self.bridges.pop() + #while self.bridges_remaining() > 0: + while args['bridge']: + + #self.current_bridge = self.bridges.pop() + self.current_bridge = args['bridge'] + try: + self.bridges.remove(self.current_bridge) + except ValueError, ve: + log.err(ve) + if self.config.config.has_key('Bridge'): log.msg("We now have %d untested bridges..." % self.bridges_remaining()) @@ -479,9 +527,6 @@ class BridgetTest(OONITest): self.pt_type) reconf.addErrback(reconfigure_fail) state.chainDeferred(reconf) - #reconfigure_bridge(state, self.current_bridge, - # self.use_pt, self.pt_type) - #current_ip = self.current_bridge.split(':', 1)[0]
else: self.config.Bridge = self.current_bridge @@ -499,10 +544,7 @@ class BridgetTest(OONITest): state.addCallback(setup_done) state.addErrback(setup_fail) state.addBoth(remove_relays, self.bridges) - #state.addCallback(remove_relays, self.bridges) - #state.addErrback(remove_relays_fail) - #state.addCallback(state_attach, self.bridges) - #state.addErrback(state_attach_fail) + return state
## XXX see txtorcon.TorControlProtocol.add_event_listener we diff --git a/ooni/utils/circuit.py b/ooni/utils/circuit.py index 0c77dd1..6ee0720 100644 --- a/ooni/utils/circuit.py +++ b/ooni/utils/circuit.py @@ -3,27 +3,27 @@ # ---------- # Utilities for working with Tor circuits. # -# This code is largely taken from the txtorcon documentation, and as -# such any and all credit should go to meejah. +# This code is largely taken from attach_streams_by_country.py in the txtorcon +# documentation, and as such any and all credit should go to meejah. Minor +# adjustments have been made to use OONI's logging system, and to build custom +# circuits without actually attaching streams. # -# :author: Mike Warren, Isis Lovecruft +# :author: Meejah, Isis Lovecruft # :license: see included license file # :version: 0.1.0-alpha # -from zope.interface import implements + +import random
from ooni.lib.txtorcon import CircuitListenerMixin, IStreamAttacher +from ooni.lib.txtorcon import TorInfo from ooni.utils import log - -import random +from zope.interface import implements
class CustomCircuit(CircuitListenerMixin): implements(IStreamAttacher)
- from txtorcon.interface import IRouterContainer - from txtorcon.interface import ICircuitContainer - def __init__(self, state): self.state = state self.waiting_circuits = []