From dfbb0a512ca95d587e8791f3cc0af56e405da4d8 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Sun, 24 Mar 2019 22:32:17 -0500 Subject: [PATCH] cleanup, work, and bugfixes for direct connections --- onionr/api.py | 7 ++-- onionr/onionrblockapi.py | 5 ++- onionr/onionrservices/__init__.py | 4 ++- onionr/onionrservices/bootstrapservice.py | 12 ++++--- onionr/onionrservices/connectionserver.py | 42 ++++++++++++++++++++--- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/onionr/api.py b/onionr/api.py index 79694238..4f7276aa 100755 --- a/onionr/api.py +++ b/onionr/api.py @@ -39,7 +39,7 @@ class FDSafeHandler(WSGIHandler): except Timeout as ex: raise -def setBindIP(filePath): +def setBindIP(filePath, writeOut=True): '''Set a random localhost IP to a specified file (intended for private or public API localhost IPs)''' if config.get('general.random_bind_ip', True): hostOctets = [str(127), str(random.randint(0x02, 0xFF)), str(random.randint(0x02, 0xFF)), str(random.randint(0x02, 0xFF))] @@ -55,8 +55,9 @@ def setBindIP(filePath): s.close() else: data = '127.0.0.1' - with open(filePath, 'w') as bindFile: - bindFile.write(data) + if writeOut: + with open(filePath, 'w') as bindFile: + bindFile.write(data) return data class PublicAPI: diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py index e7a4395b..1f890bcc 100755 --- a/onionr/onionrblockapi.py +++ b/onionr/onionrblockapi.py @@ -215,7 +215,10 @@ class Block: ''' if self.exists(): - os.remove(self.getBlockFile()) + try: + os.remove(self.getBlockFile()) + except TypeError: + pass self.getCore().removeBlock(self.getHash()) return True return False diff --git a/onionr/onionrservices/__init__.py b/onionr/onionrservices/__init__.py index 3f0e81e5..21ded6ec 100644 --- a/onionr/onionrservices/__init__.py +++ b/onionr/onionrservices/__init__.py @@ -16,8 +16,10 @@ class OnionrServices: assert self._core._utils.validateID(address) BOOTSTRAP_TRIES = 10 TRY_WAIT = 3 + base_url = 'http://%s/' % (address,) + socks = self._core.config.get('tor.socksport') for x in range(BOOTSTRAP_TRIES): - if self._core._utils.doGetRequest('http://' + address + '/ping', port=self._core.config.get('tor.socksport')) == 'pong!': + if self._core._utils.doGetRequest(base_url + 'ping', port=socks, ignoreAPI=True) == 'pong!': connectionserver.ConnectionServer(peer, address, core_inst=self._core) else: time.sleep(TRY_WAIT) diff --git a/onionr/onionrservices/bootstrapservice.py b/onionr/onionrservices/bootstrapservice.py index 33c4e8b4..f1e0b35c 100644 --- a/onionr/onionrservices/bootstrapservice.py +++ b/onionr/onionrservices/bootstrapservice.py @@ -17,11 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' +import time from gevent.pywsgi import WSGIServer, WSGIHandler from stem.control import Controller from flask import Flask import core -from netcontroller import getOpenPort +from netcontroller import getOpenPort def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): ''' @@ -38,6 +39,7 @@ def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): http_server = WSGIServer(('127.0.0.1', bootstrap_port), bootstrap_app, log=None) bootstrap_address = '' + shutdown = False @bootstrap_app.route('/ping') def get_ping(): @@ -48,20 +50,22 @@ def bootstrap_client_service(peer, core_inst=None, bootstrap_timeout=300): if core_inst._utils.validateID(address): # Set the bootstrap address then close the server bootstrap_address = address - http_server.stop() + shutdown = True + return "success" with Controller.from_port(port=core_inst.config.get('tor.controlPort')) as controller: # Connect to the Tor process for Onionr controller.authenticate(core_inst.config.get('tor.controlpassword')) # Create the v3 onion service - #response = controller.create_ephemeral_hidden_service({80: bootstrap_port}, await_publication = True, key_content = 'ED25519-V3') response = controller.create_ephemeral_hidden_service({80: bootstrap_port}, key_type = 'NEW', await_publication = True) core_inst.insertBlock(response.service_id, header='con', sign=True, encryptType='asym', asymPeer=peer, disableForward=True, expire=(core_inst._utils.getEpoch() + bootstrap_timeout)) # Run the bootstrap server - http_server.serve_forever() + threading.Thread(target=http_server.serve_forever).start() # This line reached when server is shutdown by being bootstrapped + while not shutdown and not core_inst.killSockets: + time.sleep(1) # Now that the bootstrap server has received a server, return the address return bootstrap_address diff --git a/onionr/onionrservices/connectionserver.py b/onionr/onionrservices/connectionserver.py index 32d2640a..60aff03e 100644 --- a/onionr/onionrservices/connectionserver.py +++ b/onionr/onionrservices/connectionserver.py @@ -1,5 +1,30 @@ -import stem, flask -import core +''' + Onionr - P2P Anonymous Storage Network + + This module does the second part of the bootstrap block handshake and creates the API server +''' +''' + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +''' +import threading, time +from gevent.pywsgi import WSGIServer, WSGIHandler +from stem.control import Controller +from flask import Flask +import core, logger +from netcontroller import getOpenPort +from api import setBindIP + class ConnectionServer: def __init__(self, peer, address, core_inst=None): if core_inst is None: @@ -10,10 +35,15 @@ class ConnectionServer: if not core_inst._utils.validatePubKey(peer): raise ValueError('Peer must be valid base32 ed25519 public key') - service_app = flask.Flask(__name__) + socks = core_inst.config.get('tor.socksport') # Load config for Tor socks port for proxy + service_app = Flask(__name__) # Setup Flask app for server. service_port = getOpenPort() + service_ip = setBindIP() http_server = WSGIServer(('127.0.0.1', service_port), service_app, log=None) + + # TODO define basic endpoints useful for direct connections like stats + # TODO load endpoints from plugins @service_app.route('/ping') def get_ping(): return "pong!" @@ -23,5 +53,9 @@ class ConnectionServer: controller.authenticate(core_inst.config.get('tor.controlpassword')) # Create the v3 onion service response = controller.create_ephemeral_hidden_service({80: service_port}, await_publication = True, key_type='NEW') + self.core_inst._utils.doPostRequest('http://' + address + '/bs/' + response.service_id, port=socks) logger.info('hosting on ' + response.service_id) - http_server.serve_forever() \ No newline at end of file + threading.Thread(target=http_server.serve_forever).start() + while not self.core_inst.killSockets: + time.sleep(1) + http_server.stop() \ No newline at end of file