Compare commits
4 Commits
15875d26c6
...
d6b1c98cbd
Author | SHA1 | Date | |
---|---|---|---|
|
d6b1c98cbd | ||
|
8eec2167c8 | ||
|
d48af45210 | ||
|
81a0d83b53 |
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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')
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user