From e8744f91e5176d6adf2f1fc4c2065f7041162573 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Tue, 6 Jun 2023 12:06:51 -0400 Subject: [PATCH] Hook up HTTP storage for servers listening on .onion addresses --- src/allmydata/protocol_switch.py | 14 +++++++++++--- src/allmydata/storage/http_client.py | 2 +- src/allmydata/storage/http_server.py | 11 +++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/allmydata/protocol_switch.py b/src/allmydata/protocol_switch.py index 208efec6c..941b104be 100644 --- a/src/allmydata/protocol_switch.py +++ b/src/allmydata/protocol_switch.py @@ -102,8 +102,15 @@ class _FoolscapOrHttps(Protocol, metaclass=_PretendToBeNegotiation): for location_hint in chain.from_iterable( hints.split(",") for hints in cls.tub.locationHints ): - if location_hint.startswith("tcp:"): - _, hostname, port = location_hint.split(":") + if location_hint.startswith("tcp:") or location_hint.startswith("tor:"): + scheme, hostname, port = location_hint.split(":") + if scheme == "tcp": + subscheme = None + else: + subscheme = "tor" + # If we're listening on Tor, the hostname needs to have an + # .onion TLD. + assert hostname.endswith(".onion") port = int(port) storage_nurls.add( build_nurl( @@ -111,9 +118,10 @@ class _FoolscapOrHttps(Protocol, metaclass=_PretendToBeNegotiation): port, str(swissnum, "ascii"), cls.tub.myCertificate.original.to_cryptography(), + subscheme ) ) - # TODO this is probably where we'll have to support Tor and I2P? + # TODO this is where we'll have to support Tor and I2P as well. # See https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3888#comment:9 # for discussion (there will be separate tickets added for those at # some point.) diff --git a/src/allmydata/storage/http_client.py b/src/allmydata/storage/http_client.py index 8cf79843f..cd3143924 100644 --- a/src/allmydata/storage/http_client.py +++ b/src/allmydata/storage/http_client.py @@ -369,7 +369,7 @@ class StorageClientFactory: if handler == "tcp": return Agent(reactor, tls_context_factory, pool=pool) - if handler == "tor": # TODO or nurl.scheme == "pb+tor": + if handler == "tor" or nurl.scheme == "pb+tor": assert self._tor_provider is not None if self._tor_instance is None: self._tor_instance = await self._tor_provider.get_tor_instance(reactor) diff --git a/src/allmydata/storage/http_server.py b/src/allmydata/storage/http_server.py index 924ae5a43..028ebf1c7 100644 --- a/src/allmydata/storage/http_server.py +++ b/src/allmydata/storage/http_server.py @@ -995,13 +995,20 @@ class _TLSEndpointWrapper(object): def build_nurl( - hostname: str, port: int, swissnum: str, certificate: CryptoCertificate + hostname: str, + port: int, + swissnum: str, + certificate: CryptoCertificate, + subscheme: Optional[str] = None, ) -> DecodedURL: """ Construct a HTTPS NURL, given the hostname, port, server swissnum, and x509 certificate for the server. Clients can then connect to the server using this NURL. """ + scheme = "pb" + if subscheme is not None: + scheme = f"{scheme}+{subscheme}" return DecodedURL().replace( fragment="v=1", # how we know this NURL is HTTP-based (i.e. not Foolscap) host=hostname, @@ -1013,7 +1020,7 @@ def build_nurl( "ascii", ), ), - scheme="pb", + scheme=scheme, )