[tor-commits] [ooni-probe/master] Fixed https://trac.torproject.org/projects/tor/ticket/11983 with the addition of some checks of incoherences in:

art at torproject.org art at torproject.org
Thu Aug 7 15:15:26 UTC 2014


commit a49fc8391e145b0559bad4193c0e726d49d4a409
Author: kudrom <kudrom at riseup.net>
Date:   Sun Jul 13 22:49:25 2014 +0200

    Fixed https://trac.torproject.org/projects/tor/ticket/11983 with the addition of some checks of incoherences in:
      * advanced:start_tor, tor:socks_port and tor:control_port
      * advanced:interface
---
 ooni/settings.py            |   84 +++++++++++++++++++++++++++++++++-----
 ooni/tests/test_oonicli.py  |    1 +
 ooni/tests/test_settings.py |   95 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 169 insertions(+), 11 deletions(-)

diff --git a/ooni/settings.py b/ooni/settings.py
index 07a0039..91d2f76 100644
--- a/ooni/settings.py
+++ b/ooni/settings.py
@@ -3,10 +3,15 @@ import sys
 import yaml
 import getpass
 
+from twisted.internet import defer, reactor
+from twisted.internet.endpoints import TCP4ClientEndpoint
+
 from os.path import abspath, expanduser
+from scapy.all import get_if_list
+import txtorcon
 
-from ooni import geoip
-from ooni.utils import Storage
+from ooni import otime, geoip
+from ooni.utils import Storage, log
 
 
 class OConfig(object):
@@ -93,10 +98,9 @@ class OConfig(object):
                     else:
                         w.write(line)
 
+    @defer.inlineCallbacks
     def read_config_file(self):
-        try:
-            with open(self.config_file) as f: pass
-        except IOError:
+        if not os.path.exists(self.config_file):
             print "Configuration file does not exist."
             self._create_config_file()
             self.read_config_file()
@@ -105,12 +109,70 @@ class OConfig(object):
             config_file_contents = '\n'.join(f.readlines())
             configuration = yaml.safe_load(config_file_contents)
 
-            for setting in ['basic', 'reports', 'advanced', 'privacy', 'tor']:
-                try:
-                    for k, v in configuration[setting].items():
-                        getattr(self, setting)[k] = v
-                except AttributeError:
-                    pass
+        for setting in configuration.keys():
+            if setting in dir(self):
+                for k, v in configuration[setting].items():
+                    getattr(self, setting)[k] = v
         self.set_paths()
 
+        # The incoherent checks must be performed after OConfig is in a valid state to runWithDirector
+        coherent = yield self.check_incoherences(configuration)
+        if not coherent:
+            sys.exit(6)
+
+    @defer.inlineCallbacks
+    def check_incoherences(self, configuration):
+        incoherent = []
+        deferreds = []
+
+        if not configuration['advanced']['start_tor']:
+            if not 'socks_port' in configuration['tor']:
+                incoherent.append('tor:socks_port')
+            if not 'control_port' in configuration['tor']:
+                incoherent.append('tor:control_port')
+            if 'socks_port' in configuration['tor'] and 'control_port' in configuration['tor']:
+                # Check if tor is listening in these ports
+                @defer.inlineCallbacks
+                def cb(state):
+                    timeout_call.cancel()
+                    result = yield state.protocol.get_info("net/listeners/socks")
+                    if result["net/listeners/socks"].split(':')[1] != str(configuration['tor']['socks_port']):
+                        incoherent.append('tor:socks_port')
+
+                def err(failure):
+                    incoherent.append('tor:socks_port')
+                    if timeout_call.active:
+                        timeout_call.cancel()
+
+                def timeout():
+                    incoherent.append('tor:control_port')
+                    if not d.called:
+                        d.errback()
+
+                connection = TCP4ClientEndpoint(reactor, "localhost", configuration['tor']['control_port'])
+                d = txtorcon.build_tor_connection(connection)
+                d.addCallback(cb)
+                d.addErrback(err)
+                deferreds.append(d)
+                timeout_call = reactor.callLater(30, timeout)
+
+        if configuration['advanced']['interface'] != 'auto' and configuration['advanced']['interface'] not in get_if_list():
+            incoherent.append('advanced:interface')
+
+        deferred_list = defer.DeferredList(deferreds)
+        yield deferred_list
+        if len(incoherent) > 0:
+            if len(incoherent) > 1:
+                incoherent_pretty = ", ".join(incoherent[:-1]) + ' and ' + incoherent[-1]
+            else:
+                incoherent_pretty = incoherent[0]
+            log.err("You must set properly %s in %s." % (incoherent_pretty, self.config_file))
+            defer.returnValue(False)
+        defer.returnValue(True)
+
+    def generate_pcap_filename(self, testDetails):
+        test_name, start_time = testDetails['test_name'], testDetails['start_time']
+        start_time = otime.epochToTimestamp(start_time)
+        return "report-%s-%s.%s" % (test_name, start_time, "pcap")
+
 config = OConfig()
diff --git a/ooni/tests/test_oonicli.py b/ooni/tests/test_oonicli.py
index 92da134..f4b4a49 100644
--- a/ooni/tests/test_oonicli.py
+++ b/ooni/tests/test_oonicli.py
@@ -147,6 +147,7 @@ class TestRunDirector(ConfigTestCase):
 
     @defer.inlineCallbacks
     def test_http_header_field_manipulation(self):
+        self.skipTest("Packets to 64.9.255.221:80 seems to be filtered.")
         def verify_function(entry):
             assert 'agent' in entry
             assert 'requests' in entry
diff --git a/ooni/tests/test_settings.py b/ooni/tests/test_settings.py
new file mode 100644
index 0000000..b28c1b2
--- /dev/null
+++ b/ooni/tests/test_settings.py
@@ -0,0 +1,95 @@
+import random
+
+from twisted.trial import unittest
+from twisted.internet import defer, reactor
+from twisted.internet.protocol import Protocol, Factory
+from scapy.all import get_if_list
+import txtorcon
+
+from ooni.settings import OConfig
+
+
+class TestSettings(unittest.TestCase):
+    def setUp(self):
+        self.conf = OConfig()
+        self.configuration = {'advanced': {'interface': 'auto',
+                                           'start_tor': True},
+                              'tor': {}}
+        self.silly_listener = None
+        self.tor_protocol = None
+
+    def tearDown(self):
+        if self.silly_listener is not None:
+            self.silly_listener.stopListening()
+
+    def run_tor(self):
+        def progress(percent, tag, summary):
+            ticks = int((percent/100.0) * 10.0)
+            prog = (ticks * '#') + ((10 - ticks) * '.')
+            print '%s %s' % (prog, summary)
+
+        config = txtorcon.TorConfig()
+        config.SocksPort = self.configuration['tor']['socks_port']
+        config.ControlPort = self.configuration['tor']['control_port']
+        d = txtorcon.launch_tor(config, reactor, progress_updates=progress)
+        return d
+
+    def run_silly_server(self):
+        class SillyProtocol(Protocol):
+            def __init__(self, factory):
+                self.factory = factory
+
+        class SillyFactory(Factory):
+            protocol = SillyProtocol
+
+        self.silly_listener = reactor.listenTCP(self.configuration['tor']['socks_port'], SillyFactory())
+
+    @defer.inlineCallbacks
+    def test_vanilla_configuration(self):
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, True)
+
+    @defer.inlineCallbacks
+    def test_check_incoherences_start_tor_missing_options(self):
+        self.configuration['advanced']['start_tor'] = False
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, False)
+        self.configuration['tor'] = {'socks_port': 9999}
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, False)
+        self.configuration['tor']['control_port'] = 9998
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, False)
+
+    @defer.inlineCallbacks
+    def test_check_incoherences_start_tor_correct(self):
+        self.configuration['advanced']['start_tor'] = False
+        self.configuration['tor'] = {'socks_port': 9999}
+        self.configuration['tor']['control_port'] = 9998
+        self.tor_process = yield self.run_tor()
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, True)
+        self.tor_process.transport.signalProcess('TERM')
+
+        d = defer.Deferred()
+        reactor.callLater(10, d.callback, None)
+        yield d
+
+    @defer.inlineCallbacks
+    def test_check_incoherences_start_tor_silly_listener(self):
+        self.configuration['advanced']['start_tor'] = False
+        self.configuration['tor'] = {'socks_port': 9999}
+        self.configuration['tor']['control_port'] = 9998
+        self.run_silly_server()
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, False)
+
+    @defer.inlineCallbacks
+    def test_check_incoherences_interface(self):
+        self.configuration['advanced']['interface'] = 'funky'
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, False)
+
+        self.configuration['advanced']['interface'] = random.choice(get_if_list())
+        ret = yield self.conf.check_incoherences(self.configuration)
+        self.assertEqual(ret, True)





More information about the tor-commits mailing list