[tor-commits] [ooni-probe/master] Add Telegram reachability test (#742)

art at torproject.org art at torproject.org
Fri Sep 22 18:41:07 UTC 2017


commit 3cd12a536b2e45d174fd10092ebeab69d201addd
Author: Arturo Filastò <arturo at filasto.net>
Date:   Tue Apr 4 16:36:36 2017 +0000

    Add Telegram reachability test (#742)
    
    * Add the most basic telegram reachability test
    
    * Add measurement list filter for telegram
    
    * Add Telegram test to the IM test deck
    
    * Add checks for also doing HTTP requests
    
    * This is useful to ensure that even if there is a TLS or HTTP MITM we
      are more sure that we are actually speaking to a telegram server as
      opposed to the MITM
    
    * Add support for testing Telegram Web
---
 data/decks/im.yaml                 |   3 +
 ooni/measurements.py               |  10 +++
 ooni/nettests/blocking/telegram.py | 147 +++++++++++++++++++++++++++++++++++++
 ooni/templates/httpt.py            |   4 +-
 4 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/data/decks/im.yaml b/data/decks/im.yaml
index 92984cf5..f62beda3 100644
--- a/data/decks/im.yaml
+++ b/data/decks/im.yaml
@@ -13,3 +13,6 @@ tasks:
 - name: Checks to see if Facebook Messenger is working.
   ooni:
     test_name: facebook_messenger
+- name: Checks to see if Telegram is working.
+  ooni:
+    test_name: telegram
diff --git a/ooni/measurements.py b/ooni/measurements.py
index 3407bbdc..ed09e048 100644
--- a/ooni/measurements.py
+++ b/ooni/measurements.py
@@ -20,6 +20,7 @@ class MeasurementTypes():
         "http_header_field_manipulation",
         "facebook_messenger",
         "whatsapp",
+        "telegram",
         "vanilla_tor"
     ]
 
@@ -32,6 +33,15 @@ class MeasurementTypes():
         return result
 
     @staticmethod
+    def telegram(entry):
+        result = {}
+        result['anomaly'] = True
+        if entry['test_keys'].get('telegram_tcp_blocking', None) == False:
+            result['anomaly'] = False
+        return result
+
+
+    @staticmethod
     def whatsapp(entry):
         result = {}
         result['anomaly'] = False
diff --git a/ooni/nettests/blocking/telegram.py b/ooni/nettests/blocking/telegram.py
new file mode 100644
index 00000000..9e87c992
--- /dev/null
+++ b/ooni/nettests/blocking/telegram.py
@@ -0,0 +1,147 @@
+# -*- encoding: utf-8 -*-
+
+from twisted.internet import defer, reactor
+from twisted.python import usage
+from twisted.internet.endpoints import TCP4ClientEndpoint
+
+from ooni.utils import log
+from ooni.common.http_utils import extractTitle
+from ooni.common.tcp_utils import TCPConnectFactory
+from ooni.errors import failureToString
+
+from ooni.templates import httpt
+
+# These are taken from:
+# https://github.com/telegramdesktop/tdesktop/blob/e6d94b5ee7d96a97ee5976dacb87bafd00beac1d/Telegram/SourceFiles/config.h#L205
+TELEGRAM_DCS = [
+    (1, "149.154.175.50"),
+    (2, "149.154.167.51"),
+    (3, "149.154.175.100"),
+    (4, "149.154.167.91"),
+    (5, "149.154.171.5")
+]
+
+class UsageOptions(usage.Options):
+    pass
+
+class TelegramTest(httpt.HTTPTest):
+    name = "Telegram"
+    description = ("This test examines the reachability of Telegram "
+                   "in your network.")
+    author = "Arturo Filastò"
+    version = "0.3.0"
+
+    requiresRoot = False
+    requiresTor = False
+    followRedirects = True
+    usageOptions = UsageOptions
+
+    def setUp(self):
+        self.report['telegram_tcp_blocking'] = None
+        self.report['telegram_http_blocking'] = None
+        self.report['tcp_connect'] = []
+
+    def _test_connect_to_port(self, address, port):
+        result = {
+            'ip': address,
+            'port': port,
+            'status': {
+                'success': None,
+                'failure': None
+            }
+        }
+        point = TCP4ClientEndpoint(reactor, address, port, timeout=10)
+        d = point.connect(TCPConnectFactory())
+        @d.addCallback
+        def cb(p):
+            result['status']['success'] = True
+            result['status']['failure'] = False
+            self.report['tcp_connect'].append(result)
+
+        @d.addErrback
+        def eb(failure):
+            result['status']['success'] = False
+            result['status']['failure'] = failureToString(failure)
+            self.report['tcp_connect'].append(result)
+            return failure
+
+        return d
+
+    @defer.inlineCallbacks
+    def _test_tcp_connect(self):
+        for dc_id, address in TELEGRAM_DCS:
+            dl = []
+            log.debug("Testing %s:443|80" % (address))
+            dl.append(self._test_connect_to_port(address, 443))
+            dl.append(self._test_connect_to_port(address, 80))
+
+        results = yield defer.DeferredList(dl, consumeErrors=True)
+        tcp_blocked = True
+        for success, result in results:
+            if success == True:
+                tcp_blocked = False
+
+        if tcp_blocked == True:
+            self.report['telegram_tcp_blocking'] = True
+            log.msg("Telegram servers are BLOCKED based on TCP")
+        else:
+            self.report['telegram_tcp_blocking'] = False
+            log.msg("Telegram servers are not blocked based on TCP")
+
+    @defer.inlineCallbacks
+    def _test_http_request(self):
+        http_blocked = True
+        for dc_id, address in TELEGRAM_DCS:
+            if http_blocked == False:
+                break
+            for port in [80, 443]:
+                url = 'http://{}:{}'.format(address, port)
+                try:
+                    response = yield self.doRequest(url, 'POST')
+                except Exception as exc:
+                    failure_string = failureToString(defer.failure.Failure(exc))
+                    log.err("Failed to connect to {}: {}".format(url, failure_string))
+                    continue
+                log.debug("Got back status code {}".format(response.code))
+                log.debug("{}".format(response.body))
+                if response.code == 501:
+                    http_blocked = False
+                    break
+
+        if http_blocked == True:
+            self.report['telegram_http_blocking'] = True
+            log.msg("Telegram servers are BLOCKED based on HTTP")
+        else:
+            self.report['telegram_http_blocking'] = False
+            log.msg("Telegram servers are not blocked based on HTTP")
+
+    @defer.inlineCallbacks
+    def _test_telegram_web(self, url):
+        try:
+            response = yield self.doRequest(url, 'GET')
+        except Exception as exc:
+            failure_string = failureToString(defer.failure.Failure(exc))
+            log.err("Failed to connect to whatsapp web %s" % failure_string)
+            self.report['telegram_web_failure'] = failure_string
+            self.report['telegram_web_status'] = 'blocked'
+            defer.returnValue(None)
+
+        title = extractTitle(response.body).strip()
+        if title != "Telegram Web":
+            self.report['telegram_web_status'] = 'blocked'
+
+    @defer.inlineCallbacks
+    def test_telegram_web(self):
+        self.report['telegram_web_failure'] = None
+        self.report['telegram_web_status'] = None
+
+        yield self._test_telegram_web('https://web.telegram.org/')
+        yield self._test_telegram_web('http://web.telegram.org/')
+        if self.report['telegram_web_status'] != 'blocked':
+            self.report['telegram_web_status'] = 'ok'
+
+
+    @defer.inlineCallbacks
+    def test_endpoints(self):
+        yield self._test_tcp_connect()
+        yield self._test_http_request()
diff --git a/ooni/templates/httpt.py b/ooni/templates/httpt.py
index 47d5b955..ab080c44 100644
--- a/ooni/templates/httpt.py
+++ b/ooni/templates/httpt.py
@@ -282,7 +282,9 @@ class HTTPTest(NetTestCase):
             HTTPTest.addToReport(self, request, response)
             return
         else:
-            log.debug("Got response %s" % response)
+            log.debug("Got response")
+            log.debug("code: %d" % response.code)
+            log.debug("headers: %s" % response.headers.getAllRawHeaders())
 
         if str(response.code).startswith('3'):
             self.processRedirect(response.headers.getRawHeaders('Location')[0])





More information about the tor-commits mailing list