Esempio n. 1
0
    def read_envelope(self, data):
        """
        Take an incoming message and either update the last_seen time for the
        sender or add the sender as a new contact.

        peers.py should also call this method once it's determined the network
        a message is for. That way we can inspect the 'peers' attribute and
        use read_envelope to also learn of new peers.
        """
        # Validate the senders' node ID
        seed = "%s:%i:%s" % (data['node'][1],data['node'][2],data['pubkey'])
        if data['node'][0] != long(utils.generate_node_id(seed).encode('hex'), 16):
            dht.log("\"%s\" is using an incorrect node ID." % data['node'][1], "warning")
            return

        # Learn of peers
        #  TODO: Spawn green threads to ping these nodes.
        #  NOTE: Don't permit a spammer to abuse the routing topology.
        #        This can include decrementing the senders trust rating for
        #        referring us to dead nodes.
        if 'peers' in data:
            for peer in data['peers']:
                node = dht.Node(*peer['node'], pubkey=peer['pubkey'], router=self.router)
                if node != self.source_node and self.router.is_new_node(node):
                    self.router.add_contact(node)

        # Update last_seen times for contacts or add if new
        node          = dht.Node(*data['node'], pubkey=data['pubkey'], router=self.router)
        existing_node = self.router.get_existing_node(node)
        if existing_node:
            existing_node.last_seen = time.time()
            return existing_node
        elif node != self.source_node:
            self.router.add_contact(node)
            return node
Esempio n. 2
0
    def post(self):
        """
        Unserialise the data and accept the following calls:
        PING
        CHAT
        EDIT
        APPEND
        LEAVING
        FIND_NODE
        FIND_VALUE

        APPEND signifies the requesting host has data for the given hash.
        """
        parser = restful.reqparse.RequestParser()
        parser.add_argument("data",      type=str, help="The RPC body.", default=None)
#        parser.add_argument("signature", type=str, help="Signature.", default=None)
#        parser.add_argument("pubkey",    type=str, help="Public key.", default=None)
        args = parser.parse_args()
        if not args.data:
            log("Received request from %s with no data." % request.remote_addr, "warning")
            return {}, 400

        response = []
        data = json.loads(args.data)

        if not validate_signature(data):
            log("Received message from %s with an invalid signature." % request.remote_addr, "warning")
            return "Invalid message signature.", 400

        if not 'node' in data:
            log("%s didn't provide useable information about themselves." % request.remote_addr, "warning")
            return {}, 400

        # Validate the node field for internet hosts
        if not any([request.remote_addr.startswith(subnet) for subnet in local_subnets]):
            stated_addr = data['node'][1]
            if stated_addr != request.remote_addr:
                log("Request made from %s stated it originated from %s" % (request.remote_addr, stated_addr), "warning")
                return "sicillian shrug", 418

        # Ensure this peer is using the node ID that corresponds to their ip, port and public key
        seed        = "%s:%i:%s" % (data['node'][1], data['node'][2], data['pubkey'])
        expected_id = long(generate_node_id(seed).encode('hex'), 16)
        if data['node'][0] != expected_id:
            log("%s is using an incorrect node ID." % request.remote_addr, "warning")
            log("Expecting %s but received %s" % (str(expected_id), str(data['node'][0])), "warning")
            return {}, 400

        # Determine which overlay network this request is concerned with
        if not 'network' in data:
            return {}, 400

        router = app.routes.get(data['network'], None)
        if router is None:
            return {}, 404

        # Execute the corresponding RPC handler
        for field in data.keys():
            if field.startswith('rpc_'):
                rpc_name = 'handle_%s' % field.replace('rpc_', '')
#                data[rpc_name] = data[field]
#                del data[field]
                rpc_method = getattr(router.protocol, rpc_name, None)
                if not rpc_method:
                    log("%s tried to call unknown procedure %s." % (request.remote_addr, rpc_name), "warning")
                    return {}, 400
                response = rpc_method(data)
                break

        return response