[tor-commits] [ooni-probe/master] * Fixes #6968, #6971

isis at torproject.org isis at torproject.org
Thu Oct 4 14:41:15 UTC 2012


commit fef162fe803fad2ff7eab45d321baf1086f6c980
Author: Isis Lovecruft <isis at torproject.org>
Date:   Tue Sep 25 00:07:54 2012 +0000

    * Fixes #6968, #6971
    * Found bug: first bridge doesn't get tested #6970
    * I'm trying to use trac more to keep other people up-to-date, in case that
      wasn't obviously. I hate Trac like nobody's business.
---
 ooni/plugins/bridget.py |  201 +++++++++++++++++++++++++---------------------
 ooni/utils/onion.py     |   38 +++++++---
 2 files changed, 137 insertions(+), 102 deletions(-)

diff --git a/ooni/plugins/bridget.py b/ooni/plugins/bridget.py
index cd7ba4e..83c9ed6 100644
--- a/ooni/plugins/bridget.py
+++ b/ooni/plugins/bridget.py
@@ -66,33 +66,43 @@ class PTNotFoundException(Exception):
         return sys.exit()
 
 class ValueChecker(object):
-    def port_check(self, number):
+    def port_check(self, port):
         """Check that given ports are in the allowed range."""
-        number = int(number)
-        if number not in range(1024, 65535):
+        port = int(port)
+        if port not in range(1024, 65535):
             raise ValueError("Port out of range")
+            log.err()
 
     sock_check, ctrl_check = port_check, port_check
     allowed                = "must be between 1024 and 65535."
     sock_check.coerceDoc   = "Port to use for Tor's SocksPort, "   +allowed
     ctrl_check.coerceDoc   = "Port to use for Tor's ControlPort, " +allowed
 
-    def uid_check(pluggable_transport):
-        """Check that we're not root when trying to use pluggable transports."""
+    def uid_check(self, pluggable_transport):
+        """
+        Check that we're not root when trying to use pluggable transports. If
+        we are, setuid to normal user (1000) if we're running on a posix-based
+        system, and if we're Windows just tell the user that we can't be run
+        as root with the specified options and then exit.
+        """
         uid, gid = os.getuid(), os.getgid()
         if uid == 0 and gid == 0:
             log.msg("Error: Running bridget as root with transports not allowed.")
+        if os.name == 'posix':
             log.msg("Dropping privileges to normal user...")
             os.setgid(1000)
             os.setuid(1000)
+        else:
+            sys.exit(0)
 
-    def dir_check(d):
+    def dir_check(self, d):
         """Check that the given directory exists."""
-        if not os.isdir(d):
+        if not os.path.isdir(d):
             raise ValueError("%s doesn't exist, or has wrong permissions" % d)
 
-    def file_check(f):
-        if not os.isfile(f):
+    def file_check(self, f):
+        """Check that the given file exists."""
+        if not os.path.isfile(f):
             raise ValueError("%s does not exist, or has wrong permissions" % f)
 
 class RandomPortException(Exception):
@@ -121,8 +131,9 @@ class TxtorconImportError(ImportError):
 
 class BridgetArgs(usage.Options):
     """Commandline options."""
+    global vc
     vc = ValueChecker()
-
+        
     optParameters = [
         ['bridges', 'b', None,
          'File listing bridge IP:ORPorts to test'],
@@ -227,6 +238,17 @@ class BridgetTest(OONITest):
                     else:
                         lst.append(line.replace('\n',''))
 
+        def __parse_data_dir__(data_dir):
+            if data_dir.startswith('~'):
+                data_dir = os.path.expanduser(data_dir)
+            elif data_dir.startswith('/'):
+                data_dir = os.path.join(os.getcwd(), data_dir)
+            elif data_dir.startswith('./'):
+                data_dir = os.path.abspath(data_dir)
+            else:
+                data_dir = os.path.join(os.getcwd(), data_dir)
+            return data_dir
+
         if self.local_options:
             try:
                 from ooni.lib.txtorcon import TorConfig
@@ -258,17 +280,18 @@ class BridgetTest(OONITest):
             if options['torpath']:
                 self.tor_binary = options['torpath']
 
-            if self.local_options['datadir']:
-                self.data_directory = local_options['datadir']
+            if options['datadir']:
+                self.data_directory = __parse_data_dir__(options['datadir'])
             else:
                 self.data_directory = None
 
             if options['transport']:
                 self.use_pt = True
-                log.msg("Using ClientTransportPlugin %s" % options['transport'])
+                log.msg("Using ClientTransportPlugin %s" 
+                        % options['transport'])
                 [self.pt_type, pt_exec] = options['transport'].split(' ', 1)
 
-                ## ClientTransportPlugin transport exec path-to-binary [options]
+                ## ClientTransportPlugin transport exec pathtobinary [options]
                 ## XXX we need a better way to deal with all PTs
                 if self.pt_type == "obfs2":
                     config.ClientTransportPlugin = self.pt_type + " " + pt_exec
@@ -355,6 +378,7 @@ class BridgetTest(OONITest):
             log.err(tie)
             sys.exit()
 
+        '''
         ## XXX qu'est-que fuck? ou est utiliser ce fonction? 
         def bootstrap(ctrl):
             """
@@ -364,6 +388,7 @@ class BridgetTest(OONITest):
             conf = TorConfig(ctrl)
             conf.post_bootstrap.addCallback(setup_done).addErrback(setup_fail)
             log.msg("Tor process connected, bootstrapping ...")
+        '''
 
         @defer.inlineCallbacks
         def reconfigure_bridge(state, bridge, use_pt=False, pt_type=None):
@@ -385,13 +410,19 @@ class BridgetTest(OONITest):
                     raise PTNotFoundException
 
                 controller_response = reset_tor.callback
+                controller_response.addCallback(reconfigure_done,
+                                                bridge,
+                                                reachable)
+                controller_response.addErrback(reconfigure_fail,
+                                               bridge,
+                                               reachable)
 
                 #if not controller_response:
                 #    defer.returnValue((state.callback, None))
                 #else:
                 #    defer.returnValue((state.callback, controller_response)) 
                 if controller_response == 'OK':
-                    defer.returnValue((state.callback, controller_response))
+                    defer.returnValue((state, controller_response))
                 else:
                     log.msg("TorControlProtocol responded with error:\n%s"
                             % controller_response)
@@ -400,11 +431,16 @@ class BridgetTest(OONITest):
             except Exception, e:
                 log.msg("Reconfiguring torrc with Bridge line %s failed:\n%s"
                         % (bridge, e))
+                defer.returnValue((state.callback, e))
 
-        def reconfigure_fail(state, bridge, bad):
+        def reconfigure_done(response, bridge, reachable):
+            log.msg("Reconfiguring with 'Bridge %s' successful" % bridge)
+            reachable.append(bridge)
+
+        def reconfigure_fail(response, bridge, unreachable):
             log.msg("Reconfiguring TorConfig with parameters %s failed"
                     % state)
-            bad.append(bridge)
+            unreachable.append(bridge)
 
         @defer.inlineCallbacks
         def remove_public_relays(state, bridges):
@@ -423,7 +459,7 @@ class BridgetTest(OONITest):
                                     % node)
                             bridges.remove(line)
                         except ValueError, ve:
-                            log.err(ve)
+                            log.debug(ve)
 
             if len(both) > 0:
                 try:
@@ -447,23 +483,6 @@ class BridgetTest(OONITest):
             raise NotImplemented
             #attacher.extend_circuit
 
-        #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))
-        #
-        #    log.msg("This Tor has the following %d Circuits:" 
-        #            % len(state.circuits))
-        #    for circ in state.circuits.values():
-        #        log.msg("%s" % circ)
-        #
-        #    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, path):
             log.msg("Setting up custom circuit builder...")
             attacher = CustomCircuit(state)
@@ -488,50 +507,65 @@ class BridgetTest(OONITest):
 
 
         log.msg("Bridget: initiating test ... ")
+        #defer.setDebugging(True)
 
         if self.bridges_remaining() > 0:
-            for self.current_bridge in self.bridges:
-                #self.current_bridge = bridge
+            if not 'Bridge' in self.config.config:
+                self.config.Bridge = self.bridges.pop()
+
+                ## Necessary for avoiding starting several processes:
+                self.config.save()
+                assert self.config.config.has_key('Bridge'), "NO BRIDGE"
+
+                state = start_tor(self.reactor, self.config, self.control_port,
+                                  self.tor_binary, self.data_directory)
+                #state.addCallback(remove_public_relays, self.bridges)
+                #state.callback
+                #rm_public_relays = defer.Deferred()
+                #rm_public_relays.addCallback(remove_public_relays, 
+                #                             self.bridges)
+                #state.chainDeferred(rm_public_relays)
+                #state = defer.DeferredList([state])
+                from ooni.utils.onion import __setup_done__, __setup_fail__
+                state.addCallback(__setup_done__)
+                state.addErrback(__setup_fail__)
                 
-                if not self.config.config.has_key('Bridge'):
-                    self.config.Bridge = self.current_bridge
-                    state = start_tor(self.reactor,
-                                      self.config,
-                                      self.control_port, 
-                                      self.tor_binary, 
-                                      self.data_directory)
-                    state.addCallback(remove_public_relays, self.bridges)
-                else:
-                    log.msg("We now have %d untested bridges..." 
-                            % self.bridges_remaining())
-                    reconf = defer.Deferred()
-                    reconf.addCallback(reconfigure_bridge, state,
-                                       self.current_bridge, self.use_pt,
-                                       self.pt_type)
-                    reconf.addErrback(reconfigure_fail, state,
-                                      self.current_bridge, self.bridges_down)
-                    state.chainDeferred(reconf)
-                    state.callback(controller_response)
-                    #all = []
-                    #reconf = reconfigure_bridge(state, self.current_bridge,
-                    #                            self.use_pt, self.pt_type)
-                    #reconf.addCallback(reconfigure_done)
-                    #reconf.addErrback(reconfigure_fail)
-                    #state.DeferredList(all)
-
-            if self.relays_remaining() != 0:
-                state.chainDeferred()
-
 
+        ## XXX Should do something like: if state.iscomplete
+        #if 'Bridge' in self.config.config:
+        if state and 'Bridge' in self.config.config:
+            all = []
+            for bridge in self.bridges:
+                self.current_bridge = bridge
+                log.msg("We now have %d untested bridges..." 
+                        % self.bridges_remaining())
+                #reconf = defer.Deferred()
+                #reconf.addCallback(reconfigure_bridge, state, 
+                #                   self.current_bridge, self.use_pt, 
+                #                   self.pt_type)
+                #reconf.addErrback(reconfigure_fail, state,
+                #                  self.current_bridge, self.bridges_down)
+                #state.chainDeferred(reconf)
+                #state.callback
+
+                reconf = reconfigure_bridge(state, 
+                                            self.current_bridge,
+                                            self.use_pt, 
+                                            self.pt_type)
+                all.append(reconf)
+            state.chainDeferred(defer.DeferredList(all))
+            #state.addCallback(defer.DeferredList(all))
+    
+        if self.relays_remaining() > 0:
             while self.relays_remaining() >= 3:
                 #path = list(self.relays.pop() for i in range(3))
-                #log.msg("Trying path %s" % '->'.join(map(lambda node: node, path)))
+                #log.msg("Trying path %s" % '->'.join(map(lambda node: 
+                #                                         node, path)))
                 self.current_relay = self.relays.pop()
                 for circ in state.circuits.values():
                     for node in circ.path:
                         if node == self.current_relay:
                             self.relays_up.append(self.current_relay)
-
                     if len(circ.path) < 3:
                         try:
                             parameters = (state.attacher, circ, 
@@ -545,32 +579,15 @@ class BridgetTest(OONITest):
                     else:
                         continue
 
-            return state
+        #return state
         ## still need to attach attacher to state
         ## then build circuits
 
-            ## XXX see txtorcon.TorControlProtocol.add_event_listener we
-            ##     may not need full CustomCircuit class
-            ## o if bridges and relays, use one bridge then build a circuit 
-            ##   from three relays
-            ## o if bridges only, try one bridge at a time, but don't build
-            ##   circuits, just return
-            ## o if relays only, build circuits from relays
-            #else:
-            #    try:
-            #        state.addCallback(reconfigure_bridge, self.current_bridge, 
-            #                          self.use_pt, self.pt_type)
-            #        state.addErrback(reconfigure_fail)
-            #    except TimeoutError:
-            #        log.msg("Adding %s to unreachable bridges..." 
-            #                % self.current_bridge)
-            #        self.bridges_down.append(self.current_bridge)
-            #    else:
-            #        log.msg("Adding %s to reachable bridges..." 
-            #                % self.current_bridge)
-            #        self.bridges_up.append(self.current_bridge)
-
-        #reactor.run()
+
+        reactor.run()
+
+    def control(self, experiment_result, args):
+        experiment_result.callback
 
 ## So that getPlugins() can register the Test:
 bridget = BridgetTest(None, None, None)
@@ -585,6 +602,6 @@ bridget = BridgetTest(None, None, None)
 ##       x  check if bridges are public relays
 ##       o  take bridge_desc file as input, also be able to give same
 ##          format as output
-##       x  Add assychronous timout for deferred, so that we don't wait 
+##       x  Add asynchronous timeout for deferred, so that we don't wait 
 ##          forever for bridges that don't work.
 ##       o  Add mechanism for testing through another host
diff --git a/ooni/utils/onion.py b/ooni/utils/onion.py
index 46373b4..08f27d4 100644
--- a/ooni/utils/onion.py
+++ b/ooni/utils/onion.py
@@ -17,7 +17,9 @@
 import random
 
 from ooni.lib.txtorcon import CircuitListenerMixin, IStreamAttacher
+from ooni.lib.txtorcon import TorState
 from ooni.utils        import log
+from twisted.internet  import defer
 from zope.interface    import implements
 
 
@@ -50,7 +52,7 @@ def __state_complete__(state, bridge_list=None, relay_list=None):
         return state, None
 
 def __updates__(_progress, _tag, _summary):
-    log.msg("%d%%: %s", _progress, _summary)
+    log.msg("%d%%: %s" % (_progress, _summary))
 
 def write_torrc(conf, data_dir=None):
     """
@@ -98,6 +100,7 @@ def delete_files_or_dirs(delete_list):
         except OSError:
             rmtree(temp, ignore_errors=True)
 
+ at defer.inlineCallbacks
 def start_tor(reactor, config, control_port, tor_binary, data_dir,
               report=None, progress=__updates__, process_cb=__setup_done__,
               process_eb=__setup_fail__):
@@ -162,18 +165,17 @@ def start_tor(reactor, config, control_port, tor_binary, data_dir,
     connection_creator = partial(end_point.connect, TorProtocolFactory())
     process_protocol = TorProcessProtocol(connection_creator, progress)
     process_protocol.to_delete = to_delete
-    process_protocol.addCallback(process_cb)
-    process_protocol.addErrback(process_eb)
 
     reactor.addSystemEventTrigger('before', 'shutdown',
                                   partial(delete_files_or_dirs, to_delete))
     try:
-        transport = reactor.spawnProcess(process_protocol,
-                                         tor_binary,
-                                         args=(tor_binary,'-f',torrc),
-                                         env={'HOME': data_dir},
-                                         path=data_dir)
-        transport.closeStdin()
+        transport = yield reactor.spawnProcess(process_protocol,
+                                               tor_binary,
+                                               args=(tor_binary,'-f',torrc),
+                                               env={'HOME': data_dir},
+                                               path=data_dir)
+        if transport:
+            transport.closeStdin()
     except RuntimeError as e:
         log.err("Starting Tor failed: %s" % e)
         process_protocol.connected_cb.errback(e)
@@ -182,7 +184,23 @@ def start_tor(reactor, config, control_port, tor_binary, data_dir,
         log.err("Running bridget on Windows requires pywin32: %s" % url)
         process_protocol.connected_cb.errback(e)
 
-    return process_protocol.connected_cb     ## new defer.Deferred()
+    #proc_proto = process_protocol.connected_cb
+    #proc_proto.addCallback(process_cb)
+    #proc_proto.addErrback(process_eb)
+    #
+    #d = yield process_protocol.connected_cb.addCallback(
+    #    process_cb).addErrback(
+    #    process_eb)
+    #d = yield process_protocol.connected_cb
+    #d.addCallback(process_cb)
+    #d.addErrback(process_eb)
+    #
+    #defer.returnValue(d)
+
+    d = yield process_protocol.connected_cb
+    defer.returnValue(d)
+
+    #return process_protocol.connected_cb.addCallback(process_cb).addErrback(process_eb)
     
 
 class CustomCircuit(CircuitListenerMixin):





More information about the tor-commits mailing list