def test_attributes(self): def run(self): stop(self) self.assertIsInstance(self.a_net.stethoscope_sock, socket.socket) self.assertIsInstance(self.a_net.ironhouse, Ironhouse) self.assertIsInstance(self.a_net.node, Node) self.assertEqual(self.a_net.node.public_key, self.a['curve_key']) self.assertEqual(self.b_net.node.public_key, self.b['curve_key']) self.assertEqual(self.a_net.node.id, digest(self.a['vk'])) self.assertEqual(self.b_net.node.id, digest(self.b['vk'])) t = Timer(0.01, run, [self]) t.start() self.loop.run_forever()
async def secure_server(self): log.info('Listening to secure connections at {}'.format( self.auth_port)) try: while True: received_vk, received_ip = await self.sec_sock.recv_multipart() received_vk = received_vk.decode() received_ip = received_ip.decode() log.debug( '{} got secure request {} from user claiming to be "{}"'. format(os.getenv('HOST_IP', '127.0.0.1'), received_vk, received_ip)) if self.auth_validate(received_vk) == True: public_key = self.vk2pk(received_vk) self.add_public_key(public_key) self.authorized_nodes[digest(received_vk)] = received_ip self.pk2vk[public_key] = received_vk log.debug('{} sending secure reply: {}'.format( os.getenv('HOST_IP', '127.0.0.1'), self.vk)) log.debug('{}\'s New Authorized list: {}'.format( os.getenv('HOST_IP', '127.0.0.1'), list(self.authorized_nodes.values()))) self.sec_sock.send(self.vk.encode()) else: log.warning('Unauthorized user {}({})'.format( received_ip, received_vk)) finally: self.cleanup()
def setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.a = genkeys( '06391888e37a48cef1ded85a375490df4f9b2c74f7723e88c954a055f3d2685a') self.b = genkeys( '91f7021a9e8c65ca873747ae24de08e0a7acf58159a8aa6548910fe152dab3d8') self.evil = genkeys( 'c5cb6d3ac7d644df8c72b613d57e4c47df6107989e584863b86bde47df704464') self.off = genkeys( '8ddaf072b9108444e189773e2ddcb4cbd2a76bbf3db448e55d0bfc131409a197') self.a_net = Network(sk=self.a['sk'], network_port=13321, keyname='a', wipe_certs=True, loop=self.loop, daemon=DaemonMock()) self.b_net = Network(sk=self.b['sk'], network_port=14321, keyname='b', wipe_certs=True, loop=self.loop, daemon=DaemonMock()) self.evil_net = Network(sk=self.evil['sk'], network_port=15321, keyname='evil', wipe_certs=True, loop=self.loop, daemon=DaemonMock()) self.off_node = Node(digest(self.off['vk']), ip='127.0.0.1', port=16321, public_key=self.off['curve_key'])
def __init__(self, ksize=20, alpha=3, node_id=None, discovery_mode='neighborhood', loop=None, max_peers=64, network_port=None, public_ip=None, event_sock=None, *args, **kwargs): """ Create a server instance. This will start listening on the given port. Args: ksize (int): The k parameter from the paper alpha (int): The ALPHA parameter from the paper node_id: The id for this node on the network. """ self.loop = loop if loop else asyncio.get_event_loop() asyncio.set_event_loop(self.loop) self.vkcache = {} self.ksize = ksize self.alpha = alpha self.transport = None self.protocol = None self.refresh_loop = None self.save_state_loop = None self.event_sock = event_sock self.max_peers = max_peers self.network_port = network_port self.heartbeat_port = self.network_port+HEARTBEAT_PORT_OFFSET self.ironhouse = Ironhouse(auth_port=self.network_port+AUTH_PORT_OFFSET, *args, **kwargs) self.node = Node( node_id=digest(self.ironhouse.vk), public_key=self.ironhouse.public_key, ip=public_ip or os.getenv('HOST_IP', '127.0.0.1'), port=self.network_port ) self.setup_stethoscope() self.ironhouse.setup_secure_server() self.listen() self.saveStateRegularly('state.tmp')
async def _lookup_ip(self, cmd, url, vk, *args, **kwargs): ip, node = None, None try: node, cached = await self.dht.network.lookup_ip(vk) # NOTE while secure, this is a more loose connection policy self.log.fatal('{} resolves for {}'.format(os.getenv('HOST_IP'), node)) if node and not cached: ip = node.ip if type(node) == Node else node.split(':')[0] public_key = self.dht.network.ironhouse.vk2pk(vk) authorization = await self.dht.network.ironhouse.authenticate( public_key, ip) self.log.fatal('{} -> {} is {}'.format(os.getenv('HOST_IP'), node, authorization)) if authorization != 'authorized': node = None else: n = Node(node_id=digest(vk), public_key=public_key, ip=ip, port=self.dht.network.network_port) self.dht.network.protocol.router.addContact(n) self.dht.network.connect_to_neighbor(n) self.log.fatal([ item[0] for item in self.dht.network.bootstrappableNeighbors() ]) except Exception as e: delim_line = '!' * 64 err_msg = '\n\n' + delim_line + '\n' + delim_line err_msg += '\n ERROR CAUGHT IN LOOKUP FUNCTION {}\ncalled \w args={}\nand kwargs={}\n'\ .format(args, kwargs) err_msg += '\nError Message: ' err_msg += '\n\n{}'.format(traceback.format_exc()) err_msg += '\n' + delim_line + '\n' + delim_line self.log.error(err_msg) if node is None: kwargs = cmd.kwargs callback = ReactorCommand.create_callback( callback=StateInput.LOOKUP_FAILED, **kwargs) self.log.debug( "Sending callback failure to mainthread {}".format(callback)) self.socket.send(callback.serialize()) # TODO -- send callback to SM saying hey i couldnt lookup this vk return # Send interpolated command back through pipeline ip = node.ip if type(node) == Node else node new_url = IPUtils.interpolate_url(url, ip) kwargs = cmd.kwargs kwargs['url'] = new_url new_cmd = ReactorCommand.create_cmd(envelope=cmd.envelope, **kwargs) self._execute_cmd(new_cmd)
async def lookup_ip(self, node_key): node_id = digest(node_key) cache_node = self.lookup_ip_in_cache(node_id) if cache_node: return cache_node, True if node_id == self.node.id: return self.node nearest = self.protocol.router.findNeighbors(self.node) spider = NodeSpiderCrawl(self.protocol, self.node, nearest, self.ksize, self.alpha) log.debug("Starting lookup for node_key {}".format(node_key)) res_node = await spider.find(node_id=node_id) if type(res_node) == list: res_node = None log.debug('VK {} resolves to {}'.format(node_key, res_node)) if res_node != None: self.vkcache[node_id] = res_node pk = self.ironhouse.vk2pk(node_key) return res_node, False
def welcomeIfNewNode(self, node): """ Given a new node, send it all the keys/values it should be storing, then add it to the routing table. @param node: A new node that just joined (or that we just found out about). Process: For each key in storage, get k closest nodes. If newnode is closer than the furtherst in that list, and the node for this network is closer than the closest in that list, then store the key/value on the new node (per section 2.5 of the paper) """ if not node: log.warning('This node is not welcomed.') return if not self.router.isNewNode(node): log.debug( "Skipping node {} that already exists in routing table".format( node)) return log.info("never seen %s before, adding to router", node) for key, value in self.storage.items(): keynode = Node(digest(key)) neighbors = self.router.findNeighbors(keynode) if len(neighbors) > 0: last = neighbors[-1].distanceTo(keynode) newNodeClose = node.distanceTo(keynode) < last first = neighbors[0].distanceTo(keynode) thisNodeClosest = self.sourceNode.distanceTo(keynode) < first if len(neighbors) == 0 or (newNodeClose and thisNodeClosest): asyncio.ensure_future(self.callStore(node, key, value)) self.router.addContact(node) self.network.connect_to_neighbor(node)