async def _periodically_self_advertise(self):
        while not self.is_closed:
            try:
                try:
                    await asyncio.sleep(24 * 3600)
                except asyncio.CancelledError:
                    return
                # Clean up known nodes for neighbours every 24 hours.
                async with self.lock:
                    for neighbour in list(self.neighbour_known_peers.keys()):
                        self.neighbour_known_peers[neighbour].clear()
                # Self advertise every 24 hours.
                peer = await self.server.get_peer_info()
                if peer is None:
                    continue
                timestamped_peer = [
                    TimestampedPeerInfo(
                        peer.host,
                        peer.port,
                        uint64(int(time.time())),
                    )
                ]
                msg = Message(
                    "respond_peers",
                    full_node_protocol.RespondPeers(timestamped_peer),
                )
                await self.server.send_to_all([msg], NodeType.FULL_NODE)

            except Exception as e:
                self.log.error(f"Exception in self advertise: {e}")
                self.log.error(f"Traceback: {traceback.format_exc()}")
예제 #2
0
 async def _periodically_self_advertise(self):
     while not self.is_closed:
         try:
             await asyncio.sleep(24 * 3600)
             # Clean up known nodes for neighbours every 24 hours.
             async with self.lock:
                 for neighbour in list(self.neighbour_known_peers.keys()):
                     self.neighbour_known_peers[neighbour].clear()
             # Self advertise every 24 hours.
             peer = await self.global_connections.get_local_peerinfo()
             if peer is None:
                 continue
             timestamped_peer = [
                 TimestampedPeerInfo(
                     peer.host,
                     peer.port,
                     uint64(int(time.time())),
                 )
             ]
             outbound_message = OutboundMessage(
                 NodeType.FULL_NODE,
                 Message(
                     "respond_peers_full_node",
                     full_node_protocol.RespondPeers(timestamped_peer),
                 ),
                 Delivery.BROADCAST,
             )
             if self.server is not None:
                 self.server.push_message(outbound_message)
         except Exception as e:
             self.log.error(f"Exception in self advertise: {e}")
             self.log.error(f"Traceback: {traceback.format_exc()}")
예제 #3
0
    async def request_peers(self, peer_info):
        try:
            conns = self.global_connections.get_outbound_connections()
            is_outbound = False
            for conn in conns:
                conn_peer_info = conn.get_peer_info()
                if conn_peer_info == peer_info:
                    is_outbound = True
                    break

            # Prevent a fingerprint attack: do not send peers to inbound connections.
            # This asymmetric behavior for inbound and outbound connections was introduced
            # to prevent a fingerprinting attack: an attacker can send specific fake addresses
            # to users' AddrMan and later request them by sending getaddr messages.
            # Making nodes which are behind NAT and can only make outgoing connections ignore
            # the request_peers message mitigates the attack.
            if is_outbound:
                return
            peers = await self.address_manager.get_peers()
            await self.add_peers_neighbour(peers, peer_info)
            outbound_message = OutboundMessage(
                NodeType.FULL_NODE,
                Message(
                    "respond_peers_full_node",
                    full_node_protocol.RespondPeers(peers),
                ),
                Delivery.RESPOND,
            )
            yield outbound_message
            outbound_message2 = OutboundMessage(
                NodeType.WALLET,
                Message(
                    "respond_peers_full_node",
                    full_node_protocol.RespondPeers(peers),
                ),
                Delivery.RESPOND,
            )
            yield outbound_message2
        except Exception as e:
            self.log.error(f"Request peers exception: {e}")
예제 #4
0
 async def _address_relay(self):
     while not self.is_closed:
         try:
             relay_peer, num_peers = await self.relay_queue.get()
             relay_peer_info = PeerInfo(relay_peer.host, relay_peer.port)
             if not relay_peer_info.is_valid():
                 continue
             # https://en.bitcoin.it/wiki/Satoshi_Client_Node_Discovery#Address_Relay
             connections = self.global_connections.get_full_node_connections(
             )
             hashes = []
             cur_day = int(time.time()) // (24 * 60 * 60)
             for connection in connections:
                 peer_info = connection.get_peer_info()
                 cur_hash = int.from_bytes(
                     bytes(
                         std_hash(
                             self.key.to_bytes(32, byteorder="big") +
                             peer_info.get_key() +
                             cur_day.to_bytes(3, byteorder="big"))),
                     byteorder="big",
                 )
                 hashes.append((cur_hash, connection))
             hashes.sort(key=lambda x: x[0])
             for index, (_, connection) in enumerate(hashes):
                 if index >= num_peers:
                     break
                 peer_info = connection.get_peer_info()
                 pair = (peer_info.host, peer_info.port)
                 async with self.lock:
                     if (pair in self.neighbour_known_peers
                             and relay_peer.host
                             in self.neighbour_known_peers[pair]):
                         continue
                     if pair not in self.neighbour_known_peers:
                         self.neighbour_known_peers[pair] = set()
                     self.neighbour_known_peers[pair].add(relay_peer.host)
                 if connection.node_id is None:
                     continue
                 msg = OutboundMessage(
                     NodeType.FULL_NODE,
                     Message(
                         "respond_peers_full_node",
                         full_node_protocol.RespondPeers([relay_peer]),
                     ),
                     Delivery.SPECIFIC,
                     connection.node_id,
                 )
                 self.server.push_message(msg)
         except Exception as e:
             self.log.error(f"Exception in address relay: {e}")
             self.log.error(f"Traceback: {traceback.format_exc()}")
    async def request_peers(self, peer_info: PeerInfo):
        try:

            # Prevent a fingerprint attack: do not send peers to inbound connections.
            # This asymmetric behavior for inbound and outbound connections was introduced
            # to prevent a fingerprinting attack: an attacker can send specific fake addresses
            # to users' AddrMan and later request them by sending getaddr messages.
            # Making nodes which are behind NAT and can only make outgoing connections ignore
            # the request_peers message mitigates the attack.
            if self.address_manager is None:
                return None
            peers = await self.address_manager.get_peers()
            await self.add_peers_neighbour(peers, peer_info)

            msg = Message(
                "respond_peers",
                full_node_protocol.RespondPeers(peers),
            )

            return msg
        except Exception as e:
            self.log.error(f"Request peers exception: {e}")