work on torgossip

This commit is contained in:
Kevin Froman 2021-02-08 01:52:12 +00:00
parent 18d4a87973
commit 8a6129f4e2
9 changed files with 95 additions and 34 deletions

View File

@ -9,7 +9,7 @@ from utils.identifyhome import identify_home
from .servicecontrol import create_new_service, restore_service from .servicecontrol import create_new_service, restore_service
ONION_KEY_DATABASE_FILE = identify_home() + "torgossip-onion-address-keys.db" ONION_KEY_DATABASE_FILE = identify_home() + "onion-address-keys.db"
class OnionServiceTarget(NamedTuple): class OnionServiceTarget(NamedTuple):
@ -17,27 +17,34 @@ class OnionServiceTarget(NamedTuple):
unix_socket_path: str unix_socket_path: str
class NoServices(ValueError):
pass
def load_services(controller): def load_services(controller):
db = SafeDB(ONION_KEY_DATABASE_FILE, protected=True) db = SafeDB(ONION_KEY_DATABASE_FILE, protected=True)
keys = db.keys() keys = db.db_conn.keys()
keys.remove(b'enc')
restored = []
if not keys: if not keys:
db.close() db.close()
raise ValueError("No addresses to restore") raise NoServices("No addresses to restore")
while keys: while keys:
# Not most pythonic but reduces mem usage as it runs # Not most pythonic but reduces mem usage as it runs
key = keys.pop() key = keys.pop()
if len(len) > 3: try:
try: service = unpackb(db.get(key))
service = unpackb(db.get(key)) service_id = restore_service(
restore_service( controller, service['k'], int(service['p']),
controller, service['k'], service['p'], unix_socket=service['s'])[0]
unix_socket=service['s']) restored.append((service_id, service['s']))
except Exception as _: # noqa except Exception as _: # noqa
db.close() db.close()
raise raise
db.close() db.close()
return restored
def run_new_and_store_service(controller, target: OnionServiceTarget) -> bytes: def run_new_and_store_service(controller, target: OnionServiceTarget) -> bytes:

View File

@ -27,16 +27,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
def _add_ephemeral_service( def _add_ephemeral_service(
controller: 'Controller', virtual_port, target, key_content=None): controller: 'Controller', virtual_port, target, key_content=None):
key_type = "ED25519-V3" key_type = "NEW"
if not key_content: if not key_content:
key_type = "NEW" key_content = "ED25519-V3"
else:
key_type = "ED25519-V3"
hs = controller.create_ephemeral_hidden_service( hs = controller.create_ephemeral_hidden_service(
{virtual_port: target}, {virtual_port: target},
key_type=key_type, key_type=key_type,
key_content=key_content, key_content=key_content,
await_publication=True,
detached=True detached=True
) )
return (hs.service_id, hs.private_key) return (hs.service_id, hs.private_key)
@ -65,10 +67,15 @@ def restore_service(
bind_location: str = None): bind_location: str = None):
if unix_socket and bind_location or (not unix_socket and not bind_location): if unix_socket and bind_location or (not unix_socket and not bind_location):
raise ValueError("Must pick unix socket or ip:port, and not both") raise ValueError("Must pick unix socket or ip:port, and not both")
key = base64.b64encode(key)
key = base64.b64encode(key).decode()
target = unix_socket target = unix_socket
if bind_location: if bind_location:
target = bind_location target = bind_location
return _add_ephemeral_service(controller, virtual_port, target, key) if not target.startswith("unix:"):
target = "unix:" + target
return _add_ephemeral_service(
controller, virtual_port, target, key_content=key)

View File

@ -18,6 +18,7 @@ from deadsimplekv import DeadSimpleKV
import psutil import psutil
import config import config
from netcontroller.torcontrol import onionservice, torcontroller
import onionrstatistics import onionrstatistics
from onionrstatistics import serializeddata from onionrstatistics import serializeddata
import apiservers import apiservers
@ -246,6 +247,13 @@ def daemon():
_setup_online_mode(use_existing_tor, net, security_level) _setup_online_mode(use_existing_tor, net, security_level)
_show_info_messages() _show_info_messages()
with torcontroller.get_controller() as c:
try:
onionservice.load_services(c)
except onionservice.NoServices:
pass
logger.info( logger.info(
"Onionr daemon is running under " + str(os.getpid()), terminal=True) "Onionr daemon is running under " + str(os.getpid()), terminal=True)
events.event('init', threaded=False, data=shared_state) events.event('init', threaded=False, data=shared_state)

View File

@ -4,6 +4,7 @@ Torgossip client
Create streams to random peers Create streams to random peers
""" """
import sys
from base64 import b32encode from base64 import b32encode
from os import path from os import path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -17,6 +18,9 @@ from netcontroller.torcontrol import torcontroller
if TYPE_CHECKING: if TYPE_CHECKING:
from .peerdb import TorGossipPeers from .peerdb import TorGossipPeers
from stem.control import Controller from stem.control import Controller
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
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
@ -31,6 +35,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
controller = torcontroller.get_controller()
def _add_bootstrap_peers(peer_db: 'TorGossipPeers'): def _add_bootstrap_peers(peer_db: 'TorGossipPeers'):
@ -38,13 +43,18 @@ def _add_bootstrap_peers(peer_db: 'TorGossipPeers'):
with open(bootstap_peers, 'r') as bs_peers: with open(bootstap_peers, 'r') as bs_peers:
peers = bs_peers.split(',') peers = bs_peers.split(',')
for peer in peers: for peer in peers:
if peer: try:
peer_db.get(peer)
except KeyError:
pass
else:
continue
if peer and service_online_recently(controller, peer):
peer_db.add_peer(peer) peer_db.add_peer(peer)
def _client_pool(shared_state, controller: 'Controller'): def _client_pool(shared_state, socket_pool: dict):
peer_db: 'TorGossipPeers' = shared_state.get_by_string('TorGossipPeers') peer_db: 'TorGossipPeers' = shared_state.get_by_string('TorGossipPeers')
socket_pool = {}
socks_port = shared_state.get_by_string('NetController').socksPort socks_port = shared_state.get_by_string('NetController').socksPort
peers = peer_db.get_highest_score_peers(20) peers = peer_db.get_highest_score_peers(20)
@ -61,20 +71,23 @@ def _client_pool(shared_state, controller: 'Controller'):
try: try:
socket_pool[peer] = s.connect( socket_pool[peer] = s.connect(
(b32encode(peer).decode().lower() + ".onion", 2021)) (b32encode(peer).decode().lower() + ".onion", 2021))
except socket.GeneralProxyError: except socket.GeneralProxyError:
s.close() s.close()
def client_loop(shared_state, socket_pool):
def client_pool(shared_state): while True:
controller = torcontroller.get_controller() if not socket_pool:
# Pass the stem Controller and then close it even if an exception raises _client_pool(shared_state, socket_pool)
try:
_client_pool(shared_state, controller)
except Exception:
raise
finally:
# Calls before the above raise no matter what
controller.close()
def start_client(shared_state):
# add boot strap peers to db if we need peers
_add_bootstrap_peers(shared_state.get_by_string('TorGossipPeers'))
# create and fill pool of sockets to peers (over tor socks)
socket_pool = {}
_client_pool(shared_state, socket_pool)
client_loop(shared_state, socket_pool)

View File

@ -1,3 +1,4 @@
from utils.identifyhome import identify_home from utils.identifyhome import identify_home
SERVER_SOCKET = identify_home() + "torgossip.sock" SERVER_SOCKET = identify_home() + "torgossip.sock"
HOSTNAME_FILE = identify_home() + "torgossip-hostname"
GOSSIP_PORT = 2020 GOSSIP_PORT = 2020

View File

@ -3,14 +3,18 @@ Onionr - Private P2P Communication
Default plugin which allows users to encrypt/decrypt messages w/o using blocks Default plugin which allows users to encrypt/decrypt messages w/o using blocks
""" """
from inspect import trace from base64 import b32encode
import locale import locale
from netcontroller.torcontrol import torcontroller
locale.setlocale(locale.LC_ALL, '') locale.setlocale(locale.LC_ALL, '')
import sys import sys
import os import os
import traceback import traceback
from threading import Thread from threading import Thread
from netcontroller.torcontrol import onionservice
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from constants import SERVER_SOCKET, GOSSIP_PORT, HOSTNAME_FILE
""" """
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
@ -44,5 +48,27 @@ def on_init(api, data=None):
shared_state.get(TorGossipPeers) shared_state.get(TorGossipPeers)
hs = ""
try:
with open(HOSTNAME_FILE, "rb") as f:
hs = f.read()
if not hs:
raise FileNotFoundError
except FileNotFoundError:
with torcontroller.get_controller() as c:
try:
hs = onionservice.run_new_and_store_service(
c, onionservice.OnionServiceTarget(
GOSSIP_PORT, SERVER_SOCKET))
except Exception:
print(traceback.format_exc())
raise
with open(HOSTNAME_FILE, "wb") as hf:
hf.write(hs)
Thread(target=start_server, daemon=True, args=[shared_state]).start() Thread(target=start_server, daemon=True, args=[shared_state]).start()

View File

@ -25,7 +25,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
class TorGossipPeers: # name it this way to avoid collisions in SharedState class TorGossipPeers: # name it this way to avoid collisions in SharedState
PACK_FORMAT = "qQ" PACK_FORMAT = "qQ"

View File

@ -14,7 +14,7 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from commands import GossipCommands # noqa from commands import GossipCommands # noqa
import commandhandlers import commandhandlers
from .constants import SERVER_SOCKET from constants import SERVER_SOCKET
""" """
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