Move the ability to use Tor vs Meek into the CensorshipCircumvention class so that we can use those endpoints over Tor elsewhere later

This commit is contained in:
Miguel Jacq 2021-11-27 10:35:25 +11:00
parent 06a3599fe1
commit 55c8ada6ef
No known key found for this signature in database
GPG Key ID: EEA4341C6D97A0B6
2 changed files with 60 additions and 57 deletions

View File

@ -25,21 +25,46 @@ from .meek import MeekNotRunning
class CensorshipCircumvention(object):
"""
Connect to the Tor Moat APIs to retrieve censorship
circumvention recommendations, over the Meek client.
circumvention recommendations or the latest bridges.
We support reaching this API over Tor, or Meek
(domain fronting) if Tor is not connected.
"""
def __init__(self, common, meek, domain_fronting=True):
def __init__(self, common, meek=None, onion=None):
"""
Set up the CensorshipCircumvention object to hold
common and meek objects.
"""
self.common = common
self.meek = meek
self.common.log("CensorshipCircumvention", "__init__")
# Bail out if we requested domain fronting but we can't use meek
if domain_fronting and not self.meek.meek_proxies:
raise MeekNotRunning()
self.api_proxies = {}
if meek:
self.meek = meek
if not self.meek.meek_proxies:
raise MeekNotRunning()
else:
self.common.log(
"CensorshipCircumvention",
"__init__",
"Using Meek with CensorShipCircumvention API",
)
self.api_proxies = self.meek.meek_proxies
if onion:
self.onion = onion
if not self.onion.is_authenticated:
return False
else:
self.common.log(
"CensorshipCircumvention",
"__init__",
"Using Tor with CensorShipCircumvention API",
)
(socks_address, socks_port) = self.onion.get_tor_socks_port()
self.api_proxies = {
"http": f"socks5h://{socks_address}:{socks_port}",
"https": f"socks5h://{socks_address}:{socks_port}",
}
def request_map(self, country=False):
"""
@ -52,6 +77,8 @@ class CensorshipCircumvention(object):
Note that this API endpoint doesn't return actual bridges,
it just returns the recommended bridge type countries.
"""
if not self.api_proxies:
return False
endpoint = "https://bridges.torproject.org/moat/circumvention/map"
data = {}
if country:
@ -61,7 +88,7 @@ class CensorshipCircumvention(object):
endpoint,
json=data,
headers={"Content-Type": "application/vnd.api+json"},
proxies=self.meek.meek_proxies,
proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(
@ -95,6 +122,8 @@ class CensorshipCircumvention(object):
Optionally, a list of transports can be specified in order to
return recommended settings for just that transport type.
"""
if not self.api_proxies:
return False
endpoint = "https://bridges.torproject.org/moat/circumvention/settings"
data = {}
if country:
@ -105,7 +134,7 @@ class CensorshipCircumvention(object):
endpoint,
json=data,
headers={"Content-Type": "application/vnd.api+json"},
proxies=self.meek.meek_proxies,
proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(
@ -142,11 +171,13 @@ class CensorshipCircumvention(object):
"""
Retrieves the list of built-in bridges from the Tor Project.
"""
if not self.api_proxies:
return False
endpoint = "https://bridges.torproject.org/moat/circumvention/builtin"
r = requests.post(
endpoint,
headers={"Content-Type": "application/vnd.api+json"},
proxies=self.meek.meek_proxies,
proxies=self.api_proxies,
)
if r.status_code != 200:
self.common.log(

View File

@ -914,7 +914,8 @@ class Onion(object):
Use the CensorshipCircumvention API to fetch the latest built-in bridges
and update them in settings.
"""
got_builtin_bridges = False
builtin_bridges = False
meek = None
# Try obtaining bridges over Tor, if we're connected to it.
if self.is_authenticated:
self.common.log(
@ -922,43 +923,14 @@ class Onion(object):
"update_builtin_bridges",
"Updating the built-in bridges. Trying over Tor first",
)
(socks_address, socks_port) = self.get_tor_socks_port()
tor_proxies = {
"http": f"socks5h://{socks_address}:{socks_port}",
"https": f"socks5h://{socks_address}:{socks_port}",
}
# Request a bridge
r = requests.post(
"https://bridges.torproject.org/moat/circumvention/builtin",
headers={"Content-Type": "application/vnd.api+json"},
proxies=tor_proxies,
self.censorship_circumvention = CensorshipCircumvention(
self.common, None, self
)
if r.status_code != 200:
self.common.log(
"Onion",
"update_builtin_bridges",
f"Trying over Tor failed: status_code={r.status_code}",
)
builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
try:
builtin_bridges = r.json()
if "errors" in builtin_bridges:
self.common.log(
"Onion",
"update_builtin_bridges",
f"Trying over Tor failed: errors={builtin_bridges['errors']}",
)
else:
got_builtin_bridges = builtin_bridges
except Exception as e:
self.common.log(
"Onion",
"update_builtin_bridges",
f"Hit exception when trying over Tor: {e}",
)
if not got_builtin_bridges:
# Fall back to using Meek, without Tor
if not builtin_bridges:
# Tor was not running or it failed to hit the Tor API.
# Fall back to using Meek (domain-fronting).
self.common.log(
"Onion",
"update_builtin_bridges",
@ -966,35 +938,35 @@ class Onion(object):
)
meek = Meek(self.common)
meek.start()
self.censorship_circumvention = CensorshipCircumvention(self.common, meek)
got_builtin_bridges = (
self.censorship_circumvention.request_builtin_bridges()
self.censorship_circumvention = CensorshipCircumvention(
self.common, meek, None
)
builtin_bridges = self.censorship_circumvention.request_builtin_bridges()
meek.cleanup()
# If we got to this point, we have bridges
if got_builtin_bridges:
if builtin_bridges:
# If we got to this point, we have bridges
self.common.log(
"Onion",
"update_builtin_bridges",
f"Obtained bridges: {got_builtin_bridges}",
f"Obtained bridges: {builtin_bridges}",
)
if got_builtin_bridges["meek"]:
if builtin_bridges["meek"]:
# Meek bridge needs to be defined as "meek_lite", not "meek",
# for it to work with obfs4proxy.
# We also refer to this bridge type as 'meek-azure' in our settings.
# So first, rename the key in the dict
got_builtin_bridges["meek-azure"] = got_builtin_bridges.pop("meek")
builtin_bridges["meek-azure"] = builtin_bridges.pop("meek")
new_meek_bridges = []
# Now replace the values. They also need the url/front params appended
for item in got_builtin_bridges["meek-azure"]:
for item in builtin_bridges["meek-azure"]:
newline = item.replace("meek", "meek_lite")
new_meek_bridges.append(
f"{newline} url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com"
)
got_builtin_bridges["meek-azure"] = new_meek_bridges
builtin_bridges["meek-azure"] = new_meek_bridges
# Save the new settings
self.settings.set("bridges_builtin", got_builtin_bridges)
self.settings.set("bridges_builtin", builtin_bridges)
self.settings.save()
else:
self.common.log(