A rough implementation of onion service based on pybitmessage plugin
This commit is contained in:
parent
46f2d2d1e3
commit
4bcd7076e2
|
@ -272,6 +272,15 @@ def main():
|
|||
logging.error('Unsupported proxy schema!')
|
||||
return
|
||||
|
||||
if shared.tor:
|
||||
try:
|
||||
from . import tor
|
||||
except ImportError:
|
||||
logging.info('Failed to import tor module.', exc_info=True)
|
||||
else:
|
||||
if not tor.start_tor_service():
|
||||
logging.warning('Failed to start tor service.')
|
||||
|
||||
if shared.ip_enabled and not shared.trusted_peer:
|
||||
bootstrap_from_dns()
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class Manager(threading.Thread):
|
|||
self.last_pickled_objects = time.time()
|
||||
self.last_pickled_nodes = time.time()
|
||||
# Publish destination 5-15 minutes after start
|
||||
self.last_published_i2p_destination = \
|
||||
self.last_published_destination = \
|
||||
time.time() - 50 * 60 + random.uniform(-1, 1) * 300 # nosec B311
|
||||
|
||||
def run(self):
|
||||
|
@ -49,9 +49,10 @@ class Manager(threading.Thread):
|
|||
if now - self.last_pickled_nodes > 60:
|
||||
self.pickle_nodes()
|
||||
self.last_pickled_nodes = now
|
||||
if now - self.last_published_i2p_destination > 3600:
|
||||
if now - self.last_published_destination > 3600:
|
||||
self.publish_i2p_destination()
|
||||
self.last_published_i2p_destination = now
|
||||
self.publish_onion_peer()
|
||||
self.last_published_destination = now
|
||||
|
||||
@staticmethod
|
||||
def clean_objects():
|
||||
|
@ -290,3 +291,11 @@ class Manager(threading.Thread):
|
|||
shared.i2p_dest_obj_type, shared.i2p_dest_obj_version,
|
||||
shared.stream, dest_pub_raw)
|
||||
proofofwork.do_pow_and_publish(obj)
|
||||
|
||||
@staticmethod
|
||||
def publish_onion_peer():
|
||||
if shared.onion_hostname:
|
||||
logging.info('Publishing our onion peer')
|
||||
obj = structure.OnionPeer(
|
||||
shared.onion_hostname, shared.listening_port).to_object()
|
||||
proofofwork.do_pow_and_publish(obj)
|
||||
|
|
|
@ -31,6 +31,7 @@ onion_obj_version = 3
|
|||
|
||||
socks_proxy = None
|
||||
tor = False
|
||||
onion_hostname = ''
|
||||
|
||||
i2p_enabled = False
|
||||
i2p_transient = False
|
||||
|
|
137
minode/tor.py
Normal file
137
minode/tor.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
"""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
|
||||
|
||||
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'))
|
||||
tor_config = {
|
||||
'SocksPort': str(shared.socks_proxy.port),
|
||||
'ControlSocket': control_socket}
|
||||
|
||||
for attempt in range(50):
|
||||
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=20,
|
||||
init_msg_handler=logwrite)
|
||||
except OSError:
|
||||
if not attempt:
|
||||
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
|
||||
|
||||
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 True
|
||||
|
||||
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 True
|
Loading…
Reference in New Issue
Block a user