148 lines
4.3 KiB
Python
148 lines
4.3 KiB
Python
"""Tor specific procedures"""
|
|
import logging
|
|
import os
|
|
import stat
|
|
import random
|
|
import tempfile
|
|
|
|
import stem
|
|
import stem.control
|
|
import stem.process
|
|
import stem.util
|
|
import stem.version
|
|
|
|
from . import shared
|
|
|
|
|
|
def logwrite(line):
|
|
"""A simple log writing handler for tor messages"""
|
|
try:
|
|
level, line = line.split('[', 1)[1].split(']', 1)
|
|
except (IndexError, ValueError):
|
|
logging.warning(line)
|
|
else:
|
|
if level in ('err', 'warn'):
|
|
logging.info('(tor)%s', line)
|
|
|
|
|
|
def start_tor_service():
|
|
"""Start own tor instance and configure a hidden service"""
|
|
try:
|
|
socket_dir = os.path.join(shared.data_directory, 'tor')
|
|
os.makedirs(socket_dir, exist_ok=True)
|
|
except OSError:
|
|
try:
|
|
socket_dir = tempfile.mkdtemp()
|
|
except OSError:
|
|
logging.info('Failed to create a temp dir.')
|
|
return
|
|
|
|
if os.getuid() == 0:
|
|
logging.info('Tor is not going to start as root')
|
|
return
|
|
|
|
try:
|
|
present_permissions = os.stat(socket_dir)[0]
|
|
disallowed_permissions = stat.S_IRWXG | stat.S_IRWXO
|
|
allowed_permissions = ((1 << 32) - 1) ^ disallowed_permissions
|
|
os.chmod(socket_dir, allowed_permissions & present_permissions)
|
|
except OSError:
|
|
logging.debug('Failed to set dir permissions.')
|
|
return
|
|
|
|
stem.util.log.get_logger().setLevel(logging.WARNING)
|
|
|
|
control_socket = os.path.abspath(os.path.join(socket_dir, 'tor_control'))
|
|
port = str(shared.socks_proxy.port)
|
|
tor_config = {
|
|
'SocksPort': port,
|
|
'ControlSocket': control_socket}
|
|
|
|
for attempt in range(20):
|
|
if attempt > 0:
|
|
port = random.randint(32767, 65535) # nosec B311
|
|
tor_config['SocksPort'] = str(port)
|
|
try:
|
|
stem.process.launch_tor_with_config(
|
|
tor_config, take_ownership=True, timeout=90,
|
|
init_msg_handler=logwrite)
|
|
except OSError:
|
|
if not attempt:
|
|
if not shared.listen_for_connections:
|
|
return
|
|
try:
|
|
stem.version.get_system_tor_version()
|
|
except IOError:
|
|
return
|
|
continue
|
|
else:
|
|
logging.info('Started tor on port %s', port)
|
|
break
|
|
else:
|
|
logging.debug('Failed to start tor.')
|
|
return
|
|
|
|
if not shared.listen_for_connections:
|
|
return True
|
|
|
|
try:
|
|
controller = stem.control.Controller.from_socket_file(control_socket)
|
|
controller.authenticate()
|
|
except stem.SocketError:
|
|
logging.debug('Failed to instantiate or authenticate on controller.')
|
|
return
|
|
|
|
onionkey = onionkeytype = None
|
|
try:
|
|
with open(
|
|
os.path.join(shared.data_directory, 'onion_dest_priv.key'),
|
|
'r', encoding='ascii'
|
|
) as src:
|
|
onionkey = src.read()
|
|
logging.debug('Loaded onion service private key.')
|
|
onionkeytype = 'ED25519-V3'
|
|
except FileNotFoundError:
|
|
pass
|
|
except Exception:
|
|
logging.info(
|
|
'Error while loading onion service private key.', exc_info=True)
|
|
|
|
response = controller.create_ephemeral_hidden_service(
|
|
shared.listening_port, key_type=onionkeytype or 'NEW',
|
|
key_content=onionkey or 'BEST'
|
|
)
|
|
|
|
if not response.is_ok():
|
|
logging.info('Bad response from controller ):')
|
|
return
|
|
|
|
shared.onion_hostname = '{}.onion'.format(response.service_id)
|
|
logging.info('Started hidden service %s', shared.onion_hostname)
|
|
|
|
if onionkey:
|
|
return controller
|
|
|
|
try:
|
|
with open(
|
|
os.path.join(shared.data_directory, 'onion_dest_priv.key'),
|
|
'w', encoding='ascii'
|
|
) as src:
|
|
src.write(response.private_key)
|
|
logging.debug('Saved onion service private key.')
|
|
except Exception:
|
|
logging.warning(
|
|
'Error while saving onion service private key.', exc_info=True)
|
|
|
|
try:
|
|
with open(
|
|
os.path.join(shared.data_directory, 'onion_dest.pub'),
|
|
'w', encoding='ascii'
|
|
) as src:
|
|
src.write(response.service_id)
|
|
logging.debug('Saved onion service public key.')
|
|
except Exception:
|
|
logging.warning(
|
|
'Error while saving onion service public key.', exc_info=True)
|
|
|
|
return controller
|