From 3d93a37d0c063b0fbfea7978d16ae02709c668c4 Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Wed, 12 Jun 2019 21:35:30 -0500 Subject: [PATCH] start removing daemontools by moving node announcement to communicatorutils file, deniable block insertion now config option --- onionr/communicator.py | 15 ++-- onionr/communicatorutils/README.md | 2 + onionr/communicatorutils/announcenode.py | 84 +++++++++++++++++++ onionr/communicatorutils/onionrdaemontools.py | 63 +------------- 4 files changed, 96 insertions(+), 68 deletions(-) create mode 100644 onionr/communicatorutils/announcenode.py diff --git a/onionr/communicator.py b/onionr/communicator.py index 5f31fc3c..e958d387 100755 --- a/onionr/communicator.py +++ b/onionr/communicator.py @@ -25,7 +25,7 @@ import onionrexceptions, onionrpeers, onionrevents as events, onionrplugins as p from communicatorutils import onionrdaemontools, servicecreator, onionrcommunicatortimers from communicatorutils import downloadblocks, lookupblocks, lookupadders from communicatorutils import servicecreator, connectnewpeers, uploadblocks -from communicatorutils import daemonqueuehandler +from communicatorutils import daemonqueuehandler, announcenode import onionrservices, onionr, onionrproofs OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers @@ -60,6 +60,8 @@ class OnionrCommunicatorDaemon: self.connectTimes = {} self.peerProfiles = [] # list of peer's profiles (onionrpeers.PeerProfile instances) self.newPeers = [] # Peers merged to us. Don't add to db until we know they're reachable + self.announceProgress = {} + self.announceCache = {} # amount of threads running by name, used to prevent too many self.threadCounts = {} @@ -121,7 +123,7 @@ class OnionrCommunicatorDaemon: OnionrCommunicatorTimers(self, self.uploadBlock, 10, requiresPeer=True, maxThreads=1) # Timer to process the daemon command queue - OnionrCommunicatorTimers(self, self.daemonCommands, 6, maxThreads=1) + OnionrCommunicatorTimers(self, self.daemonCommands, 6, maxThreads=3) # Timer that kills Onionr if the API server crashes OnionrCommunicatorTimers(self, self.detectAPICrash, 30, maxThreads=1) @@ -136,7 +138,9 @@ class OnionrCommunicatorDaemon: self.services = None # This timer creates deniable blocks, in an attempt to further obfuscate block insertion metadata - deniableBlockTimer = OnionrCommunicatorTimers(self, self.daemonTools.insertDeniableBlock, 180, requiresPeer=True, maxThreads=1) + if config.get('general.insert_deniable_blocks', True): + deniableBlockTimer = OnionrCommunicatorTimers(self, self.daemonTools.insertDeniableBlock, 180, requiresPeer=True, maxThreads=1) + deniableBlockTimer.count = (deniableBlockTimer.frequency - 175) # Timer to check for connectivity, through Tor to various high-profile onion services netCheckTimer = OnionrCommunicatorTimers(self, self.daemonTools.netCheck, 600) @@ -144,7 +148,7 @@ class OnionrCommunicatorDaemon: # Announce the public API server transport address to other nodes if security level allows if config.get('general.security_level', 1) == 0: # Default to high security level incase config breaks - announceTimer = OnionrCommunicatorTimers(self, self.daemonTools.announceNode, 3600, requiresPeer=True, maxThreads=1) + announceTimer = OnionrCommunicatorTimers(self, announcenode.announce_node, 3600, myArgs=[self], requiresPeer=True, maxThreads=1) announceTimer.count = (announceTimer.frequency - 120) else: logger.debug('Will not announce node.') @@ -158,7 +162,6 @@ class OnionrCommunicatorDaemon: # Adjust initial timer triggers peerPoolTimer.count = (peerPoolTimer.frequency - 1) cleanupTimer.count = (cleanupTimer.frequency - 60) - deniableBlockTimer.count = (deniableBlockTimer.frequency - 175) blockCleanupTimer.count = (blockCleanupTimer.frequency - 5) # Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking @@ -358,7 +361,7 @@ class OnionrCommunicatorDaemon: def announce(self, peer): '''Announce to peers our address''' - if self.daemonTools.announceNode() == False: + if announcenode.announce_node(self) == False: logger.warn('Could not introduce node.') def detectAPICrash(self): diff --git a/onionr/communicatorutils/README.md b/onionr/communicatorutils/README.md index 2bd7caf1..5f37a122 100644 --- a/onionr/communicatorutils/README.md +++ b/onionr/communicatorutils/README.md @@ -4,6 +4,8 @@ The files in this submodule handle various subtasks and utilities for the onionr ## Files: +announcenode.py: Uses a communicator instance to announce our transport address to connected nodes + connectnewpeers.py: takes a communicator instance and has it connect to as many peers as needed, and/or to a new specified peer. daemonqueuehandler.py: checks for new commands in the daemon queue and processes them accordingly. diff --git a/onionr/communicatorutils/announcenode.py b/onionr/communicatorutils/announcenode.py new file mode 100644 index 00000000..6ba136ba --- /dev/null +++ b/onionr/communicatorutils/announcenode.py @@ -0,0 +1,84 @@ +''' + Onionr - Private P2P Communication + + Use a communicator instance to announce our transport address to connected nodes +''' +''' + 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 base64 +import onionrproofs, logger +from etc import onionrvalues + +def announce_node(daemon): + '''Announce our node to our peers''' + ov = onionrvalues.OnionrValues() + retData = False + announceFail = False + + # Do not let announceCache get too large + if len(daemon.announceCache) >= 10000: + daemon.announceCache.popitem() + + if daemon._core.config.get('general.security_level', 0) == 0: + # Announce to random online peers + for i in daemon.onlinePeers: + if not i in daemon.announceCache and not i in daemon.announceProgress: + peer = i + break + else: + peer = daemon.pickOnlinePeer() + + for x in range(1): + if x == 1 and daemon._core.config.get('i2p.host'): + ourID = daemon._core.config.get('i2p.own_addr').strip() + else: + ourID = daemon._core.hsAddress.strip() + + url = 'http://' + peer + '/announce' + data = {'node': ourID} + + combinedNodes = ourID + peer + if ourID != 1: + #TODO: Extend existingRand for i2p + existingRand = daemon._core._utils.bytesToStr(daemon._core.getAddressInfo(peer, 'powValue')) + # Reset existingRand if it no longer meets the minimum POW + if type(existingRand) is type(None) or not existingRand.endswith('0' * ov.announce_pow): + existingRand = '' + + if peer in daemon.announceCache: + data['random'] = self.announceCache[peer] + elif len(existingRand) > 0: + data['random'] = existingRand + else: + daemon.announceProgress[peer] = True + proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=ov.announce_pow) + del daemon.announceProgress[peer] + try: + data['random'] = base64.b64encode(proof.waitForResult()[1]) + except TypeError: + # Happens when we failed to produce a proof + logger.error("Failed to produce a pow for announcing to " + peer) + announceFail = True + else: + daemon.announceCache[peer] = data['random'] + if not announceFail: + logger.info('Announcing node to ' + url) + if daemon._core._utils.doPostRequest(url, data) == 'Success': + logger.info('Successfully introduced node to ' + peer) + retData = True + daemon._core.setAddressInfo(peer, 'introduced', 1) + daemon._core.setAddressInfo(peer, 'powValue', data['random']) + daemon.decrementThreadCount('announceNode') + return retData \ No newline at end of file diff --git a/onionr/communicatorutils/onionrdaemontools.py b/onionr/communicatorutils/onionrdaemontools.py index b18edd87..c0e74df3 100755 --- a/onionr/communicatorutils/onionrdaemontools.py +++ b/onionr/communicatorutils/onionrdaemontools.py @@ -1,7 +1,7 @@ ''' Onionr - Private P2P Communication - Contains the CommunicatorUtils class which contains useful functions for the communicator daemon + Contains the DaemonTools class ''' ''' This program is free software: you can redistribute it and/or modify @@ -37,67 +37,6 @@ class DaemonTools: self.announceProgress = {} self.announceCache = {} - def announceNode(self): - '''Announce our node to our peers''' - retData = False - announceFail = False - - # Do not let announceCache get too large - if len(self.announceCache) >= 10000: - self.announceCache.popitem() - - if self.daemon._core.config.get('general.security_level', 0) == 0: - # Announce to random online peers - for i in self.daemon.onlinePeers: - if not i in self.announceCache and not i in self.announceProgress: - peer = i - break - else: - peer = self.daemon.pickOnlinePeer() - - for x in range(1): - if x == 1 and self.daemon._core.config.get('i2p.host'): - ourID = self.daemon._core.config.get('i2p.own_addr').strip() - else: - ourID = self.daemon._core.hsAddress.strip() - - url = 'http://' + peer + '/announce' - data = {'node': ourID} - - combinedNodes = ourID + peer - if ourID != 1: - #TODO: Extend existingRand for i2p - existingRand = self.daemon._core._utils.bytesToStr(self.daemon._core.getAddressInfo(peer, 'powValue')) - # Reset existingRand if it no longer meets the minimum POW - if type(existingRand) is type(None) or not existingRand.endswith('0' * ov.announce_pow): - existingRand = '' - - if peer in self.announceCache: - data['random'] = self.announceCache[peer] - elif len(existingRand) > 0: - data['random'] = existingRand - else: - self.announceProgress[peer] = True - proof = onionrproofs.DataPOW(combinedNodes, forceDifficulty=ov.announce_pow) - del self.announceProgress[peer] - try: - data['random'] = base64.b64encode(proof.waitForResult()[1]) - except TypeError: - # Happens when we failed to produce a proof - logger.error("Failed to produce a pow for announcing to " + peer) - announceFail = True - else: - self.announceCache[peer] = data['random'] - if not announceFail: - logger.info('Announcing node to ' + url) - if self.daemon._core._utils.doPostRequest(url, data) == 'Success': - logger.info('Successfully introduced node to ' + peer) - retData = True - self.daemon._core.setAddressInfo(peer, 'introduced', 1) - self.daemon._core.setAddressInfo(peer, 'powValue', data['random']) - self.daemon.decrementThreadCount('announceNode') - return retData - def netCheck(self): '''Check if we are connected to the internet or not when we can't connect to any peers''' if len(self.daemon.onlinePeers) == 0: