Compare commits

...

4 Commits

Author SHA1 Message Date
Kevin F
d6b1c98cbd Ping loop while brainstorming. 2022-02-22 14:34:19 -06:00
Kevin F
8eec2167c8 Tor can now initialize peers 2022-02-21 15:15:26 -06:00
Kevin F
d48af45210 better error handling in plugin importing 2022-02-18 14:40:00 -06:00
Kevin F
81a0d83b53 Fix import in getsocks 2022-02-18 14:39:46 -06:00
10 changed files with 85 additions and 31 deletions

View File

@ -1,3 +1,4 @@
from time import sleep
from typing import TYPE_CHECKING, Set from typing import TYPE_CHECKING, Set
from os import urandom from os import urandom
import queue import queue
@ -45,3 +46,5 @@ def start_gossip_threads(
add_onionr_thread( add_onionr_thread(
gossip_client, 1, peer_set, block_queue, seed, initial_sleep=0) gossip_client, 1, peer_set, block_queue, seed, initial_sleep=0)
onionrplugins.events.event('gossip_start', data=peer_set, threaded=True) onionrplugins.events.event('gossip_start', data=peer_set, threaded=True)
sleep(4)
onionrplugins.events.event('bootstrap', data=peer_set)

View File

@ -2,8 +2,10 @@
Dandelion ++ Gossip client logic Dandelion ++ Gossip client logic
""" """
import traceback
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Set from typing import Set
from time import sleep
from queue import Queue from queue import Queue
@ -11,7 +13,9 @@ if TYPE_CHECKING:
from onionrblocks import Block from onionrblocks import Block
from .peer import Peer from .peer import Peer
import logger
import onionrplugins import onionrplugins
from .commands import GossipCommands
""" """
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -28,9 +32,37 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
def gossip_client( def gossip_client(
peer_set: Set['Peer'], peer_set: Set['Peer'],
block_queue: Queue['Block'], block_queue: Queue['Block'],
dandelion_seed: bytes): dandelion_seed: bytes):
onionrplugins.events.event('') """
Gossip client does the following:
Stem new blocks we created or downloaded *during stem phase*
Stream new blocks
"""
remove_peers = []
while True:
remove_peers.clear()
for peer in peer_set:
try:
sock = peer.get_socket()
except Exception:
logger.warn("Lost connection to " + peer.transport_address)
logger.warn(traceback.format_exc())
remove_peers.append(peer)
break
sock.sendall(int(GossipCommands.PING).to_bytes(1, 'big'))
if sock.recv(10) == b"PONG":
print("Got ping at peer")
while len(remove_peers):
try:
peer_set.remove(remove_peers.pop())
except KeyError:
pass
sleep(30)
return

View File

@ -1,9 +1,10 @@
from enum import Enum, auto from enum import IntEnum, auto
class GossipCommands(Enum): class GossipCommands(IntEnum):
PING = 1 PING = 1
ANNOUNCE = auto() ANNOUNCE = auto()
PEER_EXCHANGE = auto() PEER_EXCHANGE = auto()
STREAM_BLOCKS = auto() STREAM_BLOCKS = auto()
PUT_BLOCKS = auto() PUT_BLOCKS = auto()
CLOSE = auto()

View File

@ -33,10 +33,19 @@ def gossip_server(
async def peer_connected(reader, writer): async def peer_connected(reader, writer):
while True: while True:
cmd = asyncio.wait_for(await reader.read(1), 30) try:
match cmd: cmd = await asyncio.wait_for(reader.read(1), 60)
except asyncio.exceptions.CancelledError:
writer.close()
cmd = int.from_bytes(cmd, 'big')
if cmd == b'' or cmd == 0:
continue
match GossipCommands(cmd):
case GossipCommands.PING: case GossipCommands.PING:
writer.write(b'PONG') writer.write(b'PONG')
case GossipCommands.CLOSE:
writer.close()
await writer.drain() await writer.drain()

View File

@ -18,6 +18,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
''' '''
import os, re, importlib import os, re, importlib
import traceback
from . import onionrevents as events from . import onionrevents as events
import config, logger import config, logger
@ -59,9 +60,7 @@ def reload(stop_event = True):
return False return False
def enable(name, start_event = True): def enable(name, start_event = True):
''' """Enable a plugin."""
Enables a plugin
'''
check() check()
@ -73,7 +72,8 @@ def enable(name, start_event = True):
except ImportError as e: # Was getting import error on Gitlab CI test "data" except ImportError as e: # Was getting import error on Gitlab CI test "data"
# NOTE: If you are experiencing issues with plugins not being enabled, it might be this resulting from an error in the module # NOTE: If you are experiencing issues with plugins not being enabled, it might be this resulting from an error in the module
# can happen inconsistently (especially between versions) # can happen inconsistently (especially between versions)
logger.debug('Failed to enable module; Import error: %s' % e) logger.error('Failed to enable module:', terminal=True)
logger.error(traceback.format_exc(), terminal=True)
return False return False
else: else:
enabled_plugins.append(name) enabled_plugins.append(name)

View File

@ -1,8 +1,9 @@
from stem.control import Controller from stem.control import Controller
from .torfilepaths import control_socket from torfilepaths import control_socket
def get_socks(): def get_socks():
with Controller.from_socket_file(control_socket) as controller: with Controller.from_socket_file(control_socket) as controller:
controller.authenticate()
return controller.get_listeners('SOCKS') return controller.get_listeners('SOCKS')

View File

@ -6,9 +6,11 @@ This default plugin handles "flow" messages
import sys import sys
import os import os
import locale import locale
from time import sleep
import traceback import traceback
from typing import Set, TYPE_CHECKING from typing import Set, TYPE_CHECKING
import base64 import base64
from threading import Thread
import stem import stem
from stem.control import Controller from stem.control import Controller
@ -18,7 +20,6 @@ from utils import readstatic
import config import config
from filepaths import gossip_server_socket_file from filepaths import gossip_server_socket_file
from gossip.peer import Peer from gossip.peer import Peer
locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_ALL, '')
@ -51,6 +52,7 @@ PLUGIN_VERSION = '0.0.0'
bootstrap_file = f'{os.path.dirname(os.path.realpath(__file__))}/bootstrap.txt' bootstrap_file = f'{os.path.dirname(os.path.realpath(__file__))}/bootstrap.txt'
class OnionrTor: class OnionrTor:
def __init__(self): def __init__(self):
return return
@ -65,20 +67,28 @@ def on_bootstrap(api, data: Set[Peer] = None):
bootstrap_nodes: Set[str] bootstrap_nodes: Set[str]
peers = data peers = data
socks_address, socks_port = get_socks()
try: try:
with open(bootstrap_file, 'r') as bootstrap_file_obj: with open(bootstrap_file, 'r') as bootstrap_file_obj:
bootstrap_nodes = set(bootstrap_file_obj.read().split(',')) bootstrap_nodes = set(bootstrap_file_obj.read().split(','))
except FileNotFoundError: except FileNotFoundError:
bootstrap_nodes = set() bootstrap_nodes = set()
while not os.path.exists(control_socket):
sleep(0.1)
socks_address, socks_port = get_socks()[0]
sleep(5)
for transport_address in bootstrap_nodes: for transport_address in bootstrap_nodes:
config.reload()
if config.get('tor.transport_address') == transport_address:
# ignore if its our own
continue
if not transport_address.endswith('.onion'): if not transport_address.endswith('.onion'):
transport_address += '.onion' transport_address += '.onion'
tor_peer = TorPeer(socks_address, socks_port, transport_address) tor_peer = TorPeer(socks_address, socks_port, transport_address)
try: try:
s = tor_peer.get_socket() tor_peer.get_socket()
except Exception as e: except Exception as e:
logger.warn( logger.warn(
f"Could not connnect to Tor peer {transport_address} " + f"Could not connnect to Tor peer {transport_address} " +
@ -87,12 +97,12 @@ def on_bootstrap(api, data: Set[Peer] = None):
logger.warn(traceback.format_exc()) logger.warn(traceback.format_exc())
continue continue
peers.add(tor_peer) peers.add(tor_peer)
logger.info(f"Connected to {len(peers)} Tor peers", terminal=True)
def on_gossip_start(api, data: Set[Peer] = None): def on_gossip_start(api, data: Set[Peer] = None):
# We don't do gossip logic # We don't do gossip logic
starttor.start_tor() starttor.start_tor()
with Controller.from_socket_file(control_socket) as controller: with Controller.from_socket_file(control_socket) as controller:
@ -105,15 +115,16 @@ def on_gossip_start(api, data: Set[Peer] = None):
if not key: if not key:
add_onion_resp = controller.create_ephemeral_hidden_service( add_onion_resp = controller.create_ephemeral_hidden_service(
{'80': f'unix:{gossip_server_socket_file}'}, {'80': f'unix:{gossip_server_socket_file}'},
key_content='BEST', key_type='NEW') key_content='BEST', key_type='NEW', detached=True)
config.set('tor.key', add_onion_resp.private_key, savefile=True) config.set('tor.key', add_onion_resp.private_key, savefile=True)
new_address = 'Generated ' new_address = 'Generated '
config.set('tor.transport_address', add_onion_resp.service_id) config.set('tor.transport_address', add_onion_resp.service_id,
savefile=True)
else: else:
try: try:
add_onion_resp = controller.create_ephemeral_hidden_service( add_onion_resp = controller.create_ephemeral_hidden_service(
{'80': f'unix:{gossip_server_socket_file}'}, {'80': f'unix:{gossip_server_socket_file}'},
key_content=key, key_type='ED25519-V3') key_content=key, key_type='ED25519-V3', detached=True)
except stem.ProtocolError: except stem.ProtocolError:
logger.error( logger.error(
"Could not start Tor transport. Try restarting Onionr", "Could not start Tor transport. Try restarting Onionr",
@ -124,4 +135,3 @@ def on_gossip_start(api, data: Set[Peer] = None):
f'{new_address}Tor transport address {add_onion_resp.service_id}' + f'{new_address}Tor transport address {add_onion_resp.service_id}' +
'.onion', '.onion',
terminal=True) terminal=True)

View File

@ -1,3 +1,5 @@
from time import sleep
import stem.process import stem.process
from utils.identifyhome import identify_home from utils.identifyhome import identify_home
@ -5,14 +7,13 @@ from utils.identifyhome import identify_home
from torfilepaths import control_socket from torfilepaths import control_socket
from torfilepaths import tor_data_dir from torfilepaths import tor_data_dir
def start_tor():
def start_tor():
tor_process = stem.process.launch_tor_with_config( tor_process = stem.process.launch_tor_with_config(
config={ config={
'SocksPort': 'auto OnionTrafficOnly', 'SocksPort': 'auto OnionTrafficOnly',
'DataDirectory': tor_data_dir, 'DataDirectory': tor_data_dir,
'ControlSocket': control_socket, 'ControlSocket': control_socket,
}, },
completion_percent=50, completion_percent=100
take_ownership=True
) )

View File

@ -4,12 +4,12 @@ import socks
class TorPeer: class TorPeer:
def __init__(self, socks_host, socks_port, onion_address): def __init__(self, socks_host, socks_port, onion_address):
self.onion_address = onion_address self.transport_address = self.onion_address = onion_address
self.socks_host = socks_host self.socks_host = socks_host
self.socks_port = socks_port self.socks_port = socks_port
def get_socket(self) -> socks.socksocket: def get_socket(self) -> socks.socksocket:
s = socks.socksocket() s = socks.socksocket()
s.set_proxy(socks.SOCKS4, self.socks_host, self.socks_host, rdns=True) s.set_proxy(socks.SOCKS4, self.socks_host, self.socks_port, rdns=True)
s.connect((self.onion_address, 80)) s.connect((self.onion_address, 80))
return s return s

View File

@ -1,6 +1,6 @@
{ {
"advanced": { "advanced": {
"security_auditing": true "security_auditing": false
}, },
"allocations": { "allocations": {
"disk": 1073741824 "disk": 1073741824
@ -12,7 +12,6 @@
"dev_mode": false, "dev_mode": false,
"display_header": true, "display_header": true,
"ephemeral_tunnels": false, "ephemeral_tunnels": false,
"hide_created_blocks": true,
"insert_deniable_blocks": true, "insert_deniable_blocks": true,
"max_block_age": 2678400, "max_block_age": 2678400,
"minimum_block_pow": 5, "minimum_block_pow": 5,
@ -22,9 +21,7 @@
"security_level": 0, "security_level": 0,
"show_notifications": true, "show_notifications": true,
"store_plaintext_blocks": true, "store_plaintext_blocks": true,
"upload_mixing": false, "use_bootstrap_list": true
"use_bootstrap_list": true,
"use_subprocess_pow_if_possible": true
}, },
"log": { "log": {
"console": { "console": {
@ -33,7 +30,7 @@
}, },
"file": { "file": {
"output": true, "output": true,
"remove_on_exit": true "remove_on_exit": false
}, },
"verbosity": "default" "verbosity": "default"
}, },