Unverified Commit c40e6e11 authored by Georg Koppen's avatar Georg Koppen
Browse files

Merge remote-tracking branch 'gitlab/merge-requests/50' into maint-1.1

parents e37c4723 cb6a8a76
......@@ -93,6 +93,10 @@ tor
sbws's owned tor pid file. (Default: ~/.sbws/tor/sbws/tor.pid)
log = STR
sbws's owned tor directory log files. (Default: ~/.sbws/tor/log)
external_control_port = INT
tor control port to connect to. Useful to run integration tests with
(Default: not set. If set, it takes preference over the control socket)
extra_lines =
sbws's tor extra configuration. (Default: None)
......@@ -66,6 +66,7 @@ control_socket = ${tor:run_dpath}/control
pid = ${tor:run_dpath}/tor.pid
# note this is a directory
log = ${tor:datadir}/log
external_control_port =
extra_lines =
......@@ -679,22 +679,8 @@ def run_speedtest(args, conf):
global rd, pool, controller
controller, _ = stem_utils.init_controller(
path=conf.getpath('tor', 'control_socket'))
if not controller:
controller = stem_utils.launch_tor(conf)
'Is sbws already running? '
'We found an existing Tor process at %s. We are not going to '
'launch Tor, nor are we going to try to configure it to behave '
'like we expect. This might work okay, but it also might not. '
'If you experience problems, you should try letting sbws launch '
'Tor for itself. The ability to use an already running Tor only '
'exists for sbws developers. It is expected to be broken and may '
'even lead to messed up results.',
conf.getpath('tor', 'control_socket'))
controller = stem_utils.launch_or_connect_to_tor(conf)
# When there will be a refactor where conf is global, this can be removed
# from here.
......@@ -323,7 +323,9 @@ def _validate_tor(conf):
sec = 'tor'
err_tmpl = Template('$sec/$key ($val): $e')
unvalidated_keys = [
'datadir', 'run_dpath', 'control_socket', 'pid', 'log', 'extra_lines']
'datadir', 'run_dpath', 'control_socket', 'pid', 'log',
'external_control_port', 'extra_lines',
all_valid_keys = unvalidated_keys
errors.extend(_validate_section_keys(conf, sec, all_valid_keys, err_tmpl))
return errors
......@@ -6,7 +6,6 @@ from stem import (SocketError, InvalidRequest, UnsatisfiableRequest,
ProtocolError, SocketClosed)
from stem.connection import IncorrectSocketType
import stem.process
from configparser import ConfigParser
from threading import RLock
import copy
import logging
......@@ -60,34 +59,17 @@ def remove_event_listener(controller, func):
log.exception("Exception trying to remove event %s", e)
def init_controller(port=None, path=None, set_custom_stream_settings=True):
# NOTE: we do not currently support a control port even though the rest of
# this function will pretend like port could be set.
assert port is None
# make sure only one is set
assert port is not None or path is not None
assert not (port is not None and path is not None)
# and for the one that is set, make sure it is likely valid
assert port is None or isinstance(port, int)
assert path is None or isinstance(path, str)
def init_controller(conf):
c = None
if port:
c = _init_controller_port(port)
if not c:
return None, 'Unable to reach tor on control port'
c = _init_controller_socket(path)
if not c:
return None, 'Unable to reach tor on control socket'
assert c is not None
if set_custom_stream_settings:
# These options are also set in launch_tor.
# In a future refactor they could be set in the case they are not
# already in the running instance. This way the controller_port
# could also be used.
return c, ''
# If the external control port is set, use it to initialize the controller.
control_port = conf['tor']['external_control_port']
if control_port:
control_port = int(control_port)
# If it can not connect, the program will exit here
c = _init_controller_port(control_port)
# There is no configuration for external control socket, therefore do not
# attempt to connect to the control socket.
return c
def is_bootstrapped(c):
......@@ -110,8 +92,9 @@ def _init_controller_port(port):
c = Controller.from_port(port=port)
except (IncorrectSocketType, SocketError):
return None
fail_hard("Unable to connect to control port %s.", port)
# TODO: Allow for auth via more than just CookieAuthentication
log.info("Connected to tor via port %s", port)
return c
......@@ -127,6 +110,7 @@ def _init_controller_socket(socket):
log.exception("Error initting controller socket: %s", e)
return None
# TODO: Allow for auth via more than just CookieAuthentication
log.info("Connected to tor via socket %s", socket)
return c
......@@ -197,13 +181,15 @@ def set_torrc_options_can_fail(controller):
for k, v in TORRC_OPTIONS_CAN_FAIL.items():
controller.set_conf(k, v)
except InvalidArguments as error:
except (InvalidArguments, InvalidRequest) as error:
log.debug('Ignoring option not supported by this Tor version. %s',
except ControllerError as e:
def launch_tor(conf):
assert isinstance(conf, ConfigParser)
os.makedirs(conf.getpath('tor', 'datadir'), mode=0o700, exist_ok=True)
os.makedirs(conf.getpath('tor', 'log'), exist_ok=True)
os.makedirs(conf.getpath('tor', 'run_dpath'), mode=0o700, exist_ok=True)
......@@ -229,19 +215,33 @@ def launch_tor(conf):
torrc = parse_user_torrc_config(torrc, conf['tor']['extra_lines'])
# Finally launch Tor
# If there is already a tor process running with the same control
# socket, this will exit here.
torrc, init_msg_handler=log.debug, take_ownership=True)
except Exception as e:
fail_hard('Error trying to launch tor: %s', e)
log.info("Started own tor.")
# And return a controller to it
cont = _init_controller_socket(conf.getpath('tor', 'control_socket'))
# In the case it was not possible to connect to own tor socket.
if not cont:
fail_hard('Could not connect to own tor control socket.')
return cont
def launch_or_connect_to_tor(conf):
# If connecting to an existing controller, there is no need to configure
# own tor.
cont = init_controller(conf)
if not cont:
cont = launch_tor(conf)
# Set options that can fail at runtime
# Set runtime options
log.info('Started and connected to Tor %s via %s', cont.get_version(),
conf.getpath('tor', 'control_socket'))
log.info('Started or connected to Tor %s.', cont.get_version())
return cont
......@@ -7,7 +7,7 @@ from sbws.lib.circuitbuilder import GapsCircuitBuilder as CB
from sbws.lib.destination import DestinationList
from sbws.lib.relaylist import RelayList
from sbws.util.config import _get_default_config
from sbws.util.stem import launch_tor
from sbws.util.stem import launch_or_connect_to_tor
class _PseudoArguments(argparse.Namespace):
......@@ -91,7 +91,7 @@ SafeLogging 0
def persistent_launch_tor(conf):
cont = launch_tor(conf)
cont = launch_or_connect_to_tor(conf)
return cont
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment