Source code for onbrisca.bridge_torcontrol

# SPDX-FileCopyrightText: 2022 The Tor Project, Inc.
#
# SPDX-License-Identifier: BSD-3-Clause
import asyncio
import functools
import logging
import time

import stem
from stem.control import EventType

from onbasca.onbasca.torcontrol import TorControl
from onbrisca import config
from onbrisca.models.bridge import Bridge

logger = logging.getLogger(__name__)


[docs] class BridgeTorControl(TorControl): def __init__(self, tor_config=None, controller=None): super().__init__(tor_config, controller) self.attach_stream_lock = asyncio.Lock()
[docs] def launch_or_connect_tor( self, port=None, socket=None, pw=None, tor_config=config.TOR_CONFIG, ): controller = super().launch_or_connect_tor( port, socket, pw, tor_config ) self.controller = controller return self.controller
[docs] def try_set_bridgelines( self, bridgelines, sleep_secs=config.SET_BRIDGE_SLEEP_SECS ): """ Return valid e invalid bridgelines after trying to set them to tor via the control port. """ valid_bridgelines = invalid_brigelines = [] # Set bridges one by one so that if a line can not be parsed, it is # ignored and the rest can be set. for bridgeline in bridgelines: try: self.controller.set_conf("Bridge", bridgeline) except stem.InvalidRequest as e: logger.warning( "Ignoring invalid bridge line %s: %s", bridgeline, e ) invalid_brigelines.append(bridgeline) except Exception as e: logger.exception( "Exception adding bridgeline %s: %s", bridgeline, e ) invalid_brigelines.append(bridgeline) else: valid_bridgelines.append(bridgeline) # Sleep because otherwise tor's socket get closed setting many # bridges in a row. time.sleep(sleep_secs) return valid_bridgelines, invalid_brigelines
[docs] def set_bridgelines(self, bridges, try_set=config.TRY_SET_BRIDGELINES): if not bridges: return bridgelines = Bridge.objects.bridgelines_from_bridges(bridges) # Obtain first the bridges already set to do not set duplicated bridges tor_bridgelines = self.controller.get_conf("Bridge", multiple=True) logger.debug("tor has %s bridgelines", len(tor_bridgelines)) new_bridgelines = set(bridgelines).difference(set(tor_bridgelines)) # Now validate the bridgelines either trying to set one by one with # ``try_set_bridgelines`` or parsing them first with # ``validate_bridgelines``. if try_set: valid_bridgelines, _ = self.try_set_bridgelines(new_bridgelines) else: from onbasca.bridgeline import validate_bridgelines valid_bridgelines, _ = validate_bridgelines(new_bridgelines) # Now set all the valid bridgelines logger.debug("Setting %s bridgelines.", len(valid_bridgelines)) if valid_bridgelines: self.controller.set_conf("Bridge", valid_bridgelines) self.controller.set_conf("UseBridges", "1") logger.info( "Set bridges %s", self.controller.get_conf("Bridge", multiple=True) )
[docs] async def afetch_http_head(self, path, http_client, url): logger.debug("Creating circuit with path %s.", path) try: circuit_id = self.controller.new_circuit(path, await_build=True) except ( stem.InvalidRequest, stem.CircuitExtensionFailed, stem.ProtocolError, stem.Timeout, stem.SocketClosed, ) as e: logger.debug(e) return None, e except Exception as e: logger.debug(e) return None, e logger.debug("Created circuit %s with path %s", circuit_id, path) async with self.attach_stream_lock: logger.debug("Got lock to attach stream to circuit %s", circuit_id) stream_listener = functools.partial( self.attach_stream_to_circuit, circuit_id ) logger.debug( "Adding STREAM event listener for circuit %s.", circuit_id ) self.controller.add_event_listener( stream_listener, EventType.STREAM ) logger.debug("Obtaining HTTP HEAD via circuit %s.", circuit_id) try: response = await http_client.ahead(url) except Exception as e: # Max retries exceeded with url logger.debug(e) return circuit_id, e else: logger.debug( "Attached stream to circuit %s and fetched HTTP HEAD.", circuit_id, ) return circuit_id, response finally: logger.debug( "Removing stream listener to attach circuit %s", circuit_id ) self.controller.remove_event_listener(stream_listener) logger.debug( "Released lock to attach circuit %s to stream.", circuit_id )