commit 3cd12a536b2e45d174fd10092ebeab69d201addd Author: Arturo Filastò arturo@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/e6d94b5ee7d96a97ee5976dacb8... +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://%7B%7D:%7B%7D%27.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])
tor-commits@lists.torproject.org