[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [ooni-probe/master] Add support for starting Tor via txtorcon



commit a65b6ebb7e90a4350b1a214189196d11a8371eda
Author: Arturo Filastò <art@xxxxxxxxx>
Date:   Mon Nov 26 22:49:14 2012 +0100

    Add support for starting Tor via txtorcon
    * XXX would like to be able to know if Tor is censored and add it to the
      report, this can easily be done if running launch_tor with a timeout.
      This is provided by this patch: https://github.com/meejah/txtorcon/pull/24
---
 ooni/config.py    |   10 ++++-
 ooni/runner.py    |   97 +++++++++++++++++++++++++++++++++++++++++++++++++----
 ooni/utils/net.py |   26 ++++++++++++++
 ooniprobe.conf    |    9 ++++-
 4 files changed, 132 insertions(+), 10 deletions(-)

diff --git a/ooni/config.py b/ooni/config.py
index 69842b6..edfb196 100644
--- a/ooni/config.py
+++ b/ooni/config.py
@@ -65,7 +65,13 @@ def loadConfigFile():
     advanced = Storage()
     for k, v in configuration['advanced'].items():
         advanced[k] = v
-    return basic, privacy, advanced
+
+    # Process the tor configuration options
+    tor = Storage()
+    for k, v in configuration['tor'].items():
+        tor[k] = v
+
+    return basic, privacy, advanced, tor
 
 class TestFilenameNotSet(Exception):
     pass
@@ -85,7 +91,7 @@ def generateReportFilenames():
 
 if not basic:
     # Here we make sure that we instance the config file attributes only once
-    basic, privacy, advanced = loadConfigFile()
+    basic, privacy, advanced, tor = loadConfigFile()
 
 if not resume_filename:
     resume_filename = os.path.join(get_root_path(), 'ooniprobe.resume')
diff --git a/ooni/runner.py b/ooni/runner.py
index 6ea4a86..6940ec6 100644
--- a/ooni/runner.py
+++ b/ooni/runner.py
@@ -21,12 +21,20 @@ from twisted.internet import defer
 from twisted.trial.runner import filenameToModule
 from twisted.internet import reactor, threads
 
+from txtorcon import TorProtocolFactory, TorConfig
+from txtorcon import TorState, launch_tor
+
+from ooni import config
+
+from ooni.reporter import OONIBReporter, YAMLReporter
+from ooni.reporter import OONIBReportCreationFailed
+
 from ooni.inputunit import InputUnitFactory
 from ooni.nettest import NetTestCase, NoPostProcessor
 
-from ooni import reporter, config
-
-from ooni.utils import log, checkForRoot, NotRootError, Storage
+from ooni.utils import log, checkForRoot
+from ooni.utils import NotRootError, Storage
+from ooni.utils.net import randomFreePort
 
 def processTest(obj):
     """
@@ -374,10 +382,10 @@ def runTestCases(test_cases, options, cmd_line_options):
 
     if cmd_line_options['collector']:
         log.msg("Using remote collector, please be patient while we create the report.")
-        oreporter = reporter.OONIBReporter(cmd_line_options)
+        oreporter = OONIBReporter(cmd_line_options)
     else:
         log.msg("Reporting to file %s" % config.reports.yamloo)
-        oreporter = reporter.YAMLReporter(cmd_line_options)
+        oreporter = YAMLReporter(cmd_line_options)
 
     try:
         input_unit_factory = InputUnitFactory(test_inputs)
@@ -386,7 +394,7 @@ def runTestCases(test_cases, options, cmd_line_options):
 
     try:
         yield oreporter.createReport(options)
-    except reporter.OONIBReportCreationFailed:
+    except OONIBReportCreationFailed:
         log.err("Error in creating new report")
         raise
     except Exception, e:
@@ -421,6 +429,63 @@ def runTestCases(test_cases, options, cmd_line_options):
     except Exception:
         log.exception("Problem in running test")
 
+class UnableToStartTor(Exception):
+    pass
+
+def startTor():
+
+    @defer.inlineCallbacks
+    def state_complete(state):
+        config.tor_state = state
+        log.msg("Successfully bootstrapped Tor")
+        log.debug("We now have the following circuits: ")
+        for circuit in state.circuits.values():
+            log.debug(" * %s" % circuit)
+        config.tor.socks_port = yield state.protocol.get_conf("SocksPort")
+        config.tor.control_port = yield state.protocol.get_conf("ControlPort")
+
+    def setup_failed(arg):
+        log.exception(arg)
+        raise UnableTorStartTor
+
+    def setup_complete(proto):
+        """
+        Called when we read from stdout that Tor has reached 100%.
+        """
+        log.debug("Building a TorState")
+        state = TorState(proto.tor_protocol)
+        state.post_bootstrap.addCallback(state_complete)
+        state.post_bootstrap.addErrback(setup_failed)
+        return state.post_bootstrap
+
+    def updates(prog, tag, summary):
+        log.msg("%d%%: %s" % (prog, summary))
+
+    tor_config = TorConfig()
+    if config.tor.control_port:
+        tor_config.ControlPort = config.tor.control_port
+    else:
+        control_port = int(randomFreePort())
+        tor_config.ControlPort = control_port
+        config.tor.control_port = control_port
+
+    if config.tor.socks_port:
+        tor_config.SocksPort = config.tor.socks_port
+    else:
+        socks_port = int(randomFreePort())
+        tor_config.SocksPort = socks_port
+        config.tor.socks_port = socks_port
+
+    tor_config.save()
+
+    log.debug("Setting control port as %s" % tor_config.ControlPort)
+    log.debug("Setting SOCKS port as %s" % tor_config.SocksPort)
+
+    d = launch_tor(tor_config, reactor, progress_updates=updates)
+    d.addCallback(setup_complete)
+    d.addErrback(setup_failed)
+    return d
+
 def runTest(cmd_line_options):
     config.cmd_line_options = cmd_line_options
     config.generateReportFilenames()
@@ -436,6 +501,7 @@ def runTest(cmd_line_options):
 
     classes = findTestClassesFromFile(cmd_line_options['test'])
     test_cases, options = loadTestsAndOptions(classes, cmd_line_options)
+
     if config.privacy.includepcap:
         from ooni.utils.txscapy import ScapyFactory, ScapySniffer
         try:
@@ -451,4 +517,21 @@ def runTest(cmd_line_options):
         sniffer = ScapySniffer(config.reports.pcap)
         config.scapyFactory.registerProtocol(sniffer)
 
-    return runTestCases(test_cases, options, cmd_line_options)
+    # If we should start Tor then start it. Once Tor has started we will make
+    # sure. If not we assume that it is already running
+    if config.advanced.start_tor:
+        def tor_startup_failed(failure):
+            log.err(failure)
+
+        def tor_started():
+            return runTestCases(test_cases,
+                    options, cmd_line_options)
+
+        d = startTor()
+        d.addCallback(tor_started)
+        d.addErrback(tor_startup_failed)
+        return d
+
+    else:
+        return runTestCases(test_cases,
+                options, cmd_line_options)
diff --git a/ooni/utils/net.py b/ooni/utils/net.py
index df98412..12d1939 100644
--- a/ooni/utils/net.py
+++ b/ooni/utils/net.py
@@ -10,6 +10,8 @@
 #           see attached LICENCE file
 
 import sys
+import socket
+from random import randint
 
 from zope.interface import implements
 from twisted.internet import protocol, defer
@@ -123,6 +125,30 @@ def getIfaces(platform_name=None):
     else:
         raise UnsupportedPlatform
 
+def randomFreePort(addr="127.0.0.1"):
+    """
+    Args:
+
+        addr (str): the IP address to attempt to bind to.
+
+    Returns an int representing the free port number at the moment of calling
+
+    Note: there is no guarantee that some other application will attempt to
+    bind to this port once this function has been called.
+    """
+    free = False
+    while not free:
+        port = randint(1024, 65535)
+        s = socket.socket()
+        try:
+            s.bind((addr, port))
+            free = True
+        except:
+            pass
+        s.close()
+    return port
+
+
 def checkInterfaces(ifaces=None, timeout=1):
     """
     @param ifaces:
diff --git a/ooniprobe.conf b/ooniprobe.conf
index 5fa0743..6777fde 100644
--- a/ooniprobe.conf
+++ b/ooniprobe.conf
@@ -23,9 +23,16 @@ advanced:
     geoip_data_dir: /usr/share/GeoIP/
     debug: true
     threadpool_size: 10
-    tor_socksport: 9050
+
+    tor_binary: '/usr/sbin/tor'
     # For auto detection
     interface: auto
     # Of specify a specific interface
     #interface: wlan0
+    start_tor: true
+tor:
+    #socks_port: 9050
+    #control_port: 9051
+    # Specify the absolute path to the Tor bridges to use for testing
+    bridges: bridges.list
 



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits