[tor-commits] [bridgedb/master] Avoid giving out bridges with broken tor versions.
phw at torproject.org
phw at torproject.org
Wed Jul 8 21:15:26 UTC 2020
commit 8d169fc45c8cfd7c8c9028d125bff4dbb3afafc6
Author: Philipp Winter <phw at nymity.ch>
Date: Fri Jun 12 10:05:26 2020 -0700
Avoid giving out bridges with broken tor versions.
This patch makes BridgeDB avoid giving out bridges that are affected by
the following bug: <https://bugs.torproject.org/28912>
This fixes <https://bugs.torproject.org/29184>.
---
CHANGELOG | 5 +++++
bridgedb.conf | 10 ++++++++++
bridgedb/bridges.py | 15 +++++++++++++++
bridgedb/main.py | 7 +++++++
bridgedb/parse/versions.py | 29 +++++++++++++++++++++++++++++
bridgedb/test/test_bridges.py | 27 +++++++++++++++++++++++++++
6 files changed, 93 insertions(+)
diff --git a/CHANGELOG b/CHANGELOG
index 754e2f0..c712436 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+ * FIXES https://bugs.torproject.org/29184
+ Add a new configuration option, BLACKLISTED_TOR_VERSIONS, which contains a
+ list of Tor versions. BridgeDB won't hand out bridges whose Tor version
+ is present in this blacklist.
+
* FIXES https://bugs.torproject.org/19774
Add a favicon to BridgeDB's web UI.
diff --git a/bridgedb.conf b/bridgedb.conf
index 31eb3fa..6d4839d 100644
--- a/bridgedb.conf
+++ b/bridgedb.conf
@@ -309,6 +309,16 @@ DEFAULT_TRANSPORT = 'obfs4'
# Accept-Language,[Kk]lingon
BLACKLISTED_REQUEST_HEADERS_FILE="blacklisted-request-headers.csv"
+# List of tuples that specify blacklisted tor version ranges. The first
+# element marks the start of the range and the second element marks the end.
+# Both the start *and* the end version are blocked too. If you want to block a
+# single version, have the start and end range be identical. BridgeDB won't
+# distribute bridges whose version falls within any version ranges.
+BLACKLISTED_TOR_VERSIONS = [
+ ('0.3.4', '0.3.4.9'), # See <https://bugs.torproject.org/29184>.
+ ('0.3.5', '0.3.5.6')
+]
+
# Decoy bridges that we are handing out to bots that we detected using the
# regular expressions in BLACKLISTED_REQUEST_HEADERS_FILE. The CSV file must
# have the following format:
diff --git a/bridgedb/bridges.py b/bridgedb/bridges.py
index cd01948..6ec864d 100644
--- a/bridgedb/bridges.py
+++ b/bridgedb/bridges.py
@@ -1825,3 +1825,18 @@ class Bridge(BridgeBackwardsCompatibility):
logging.info("Removing dead transport for bridge %s: %s %s:%s %s" %
(self, pt.methodname, pt.address, pt.port, pt.arguments))
self.transports.remove(pt)
+
+ def runsVersion(self, version_tuples):
+ """Return ``True`` if this bridge runs any of the given versions.
+
+ :param list version_tuples: A list of tuples that contain a minimum and
+ maximum version number (as :class:`stem.version.Version` objects),
+ each.
+ :rtype: bool
+ :returns: ``True`` if this bridge runs any of the given Tor versions
+ and ``False`` otherwise.
+ """
+ for min_version, max_version in version_tuples:
+ if min_version <= self.software <= max_version:
+ return True
+ return False
diff --git a/bridgedb/main.py b/bridgedb/main.py
index 70001a9..44d0668 100644
--- a/bridgedb/main.py
+++ b/bridgedb/main.py
@@ -38,6 +38,7 @@ from bridgedb.distributors.https.distributor import HTTPSDistributor
from bridgedb.distributors.moat.distributor import MoatDistributor
from bridgedb.parse import descriptors
from bridgedb.parse.blacklist import parseBridgeBlacklistFile
+from bridgedb.parse.versions import parseVersionsList
import bridgedb.Storage
@@ -211,6 +212,10 @@ def load(state, hashring, clear=False):
elif bridge in blacklist.keys():
logging.warn("Not distributing blacklisted Bridge %s %s:%s: %s" %
(bridge, bridge.address, bridge.orPort, blacklist[bridge]))
+ # Skip bridges that are running a blacklisted version of Tor.
+ elif bridge.runsVersion(state.BLACKLISTED_TOR_VERSIONS):
+ logging.warn("Not distributing bridge %s because it runs blacklisted "
+ "Tor version %s." % (router.fingerprint, bridge.software))
else:
# If the bridge is not running, then it is skipped during the
# insertion process.
@@ -418,6 +423,8 @@ def run(options, reactor=reactor):
proxy.loadProxiesFromFile(proxyfile, proxies, removeStale=True)
metrics.setProxies(proxies)
+ state.BLACKLISTED_TOR_VERSIONS = parseVersionsList(state.BLACKLISTED_TOR_VERSIONS)
+
logging.info("Reloading blacklisted request headers...")
antibot.loadBlacklistedRequestHeaders(config.BLACKLISTED_REQUEST_HEADERS_FILE)
logging.info("Reloading decoy bridges...")
diff --git a/bridgedb/parse/versions.py b/bridgedb/parse/versions.py
index 335e04c..832969e 100644
--- a/bridgedb/parse/versions.py
+++ b/bridgedb/parse/versions.py
@@ -23,6 +23,10 @@ bridgedb.parse.versions
..
"""
+import logging
+
+import stem.version
+
from twisted import version as _txversion
# The twisted.python.util.Version class was moved in Twisted==14.0.0 to
@@ -127,3 +131,28 @@ class Version(_Version):
str(self.minor),
str(self.micro),
str(prerelease))
+
+
+def parseVersionsList(versions_list):
+ """Turn the given version strings into stem objects.
+
+ :param list versions_list: A list of tuples. Each tuple contains a minimum
+ and maximum version number as strings.
+ :rtype: list
+ :returns: A list of tuples. Each tuple contains a minimum and maximum
+ version number as :class:`stem.version.Version` objects.
+ """
+ parsed = []
+ for v1, v2 in versions_list:
+ # We're dealing with an already-parsed version list.
+ if isinstance(v1, stem.version.Version):
+ return versions_list
+ try:
+ parsed.append(tuple([stem.version.Version(v1),
+ stem.version.Version(v2)]))
+ except ValueError:
+ logging.error("Couldn't parse BLACKLISTED_TOR_VERSIONS; "
+ "probably because of badly formatted "
+ "configuration file. Ignoring config option.")
+ return []
+ return parsed
diff --git a/bridgedb/test/test_bridges.py b/bridgedb/test/test_bridges.py
index fd14e87..82d9584 100644
--- a/bridgedb/test/test_bridges.py
+++ b/bridgedb/test/test_bridges.py
@@ -19,6 +19,8 @@ import hashlib
import os
import warnings
+import stem.version
+
from twisted.trial import unittest
from bridgedb import bridges
@@ -1837,3 +1839,28 @@ class BridgeTests(unittest.TestCase):
self.assertTrue(len(self.bridge.transports), 3)
self.assertNotIn('scramblesuit',
[pt.methodname for pt in self.bridge.transports])
+
+ def test_runsVersions(self):
+ """Calling runsVersions() should tell us if a bridge is running any of
+ the given versions.
+ """
+ self.bridge.software = stem.version.Version("0.1.2.3")
+
+ t1 = tuple([stem.version.Version("0.1.2.3"),
+ stem.version.Version("0.1.2.3")])
+ self.assertTrue(self.bridge.runsVersion([t1]))
+
+ t2 = tuple([stem.version.Version("0.1.2"),
+ stem.version.Version("0.1.2")])
+ self.assertFalse(self.bridge.runsVersion([t2]))
+
+ t3 = tuple([stem.version.Version("0.1.2"),
+ stem.version.Version("0.1.2.5")])
+ self.assertTrue(self.bridge.runsVersion([t3]))
+
+ t4 = tuple([stem.version.Version("0.2.2"),
+ stem.version.Version("0.3.1")])
+ self.assertFalse(self.bridge.runsVersion([t4]))
+
+ self.assertTrue(self.bridge.runsVersion([t1, t2, t3, t4]))
+ self.assertFalse(self.bridge.runsVersion([t2, t4]))
More information about the tor-commits
mailing list