示例#1
0
async def handshake(
    remote: kademlia.Node, privkey: datatypes.PrivateKey, token: CancelToken
) -> Tuple[bytes, bytes, BasePreImage, BasePreImage, asyncio.StreamReader,
           asyncio.StreamWriter]:  # noqa: E501
    """
    Perform the auth handshake with given remote.

    Returns the established secrets and the StreamReader/StreamWriter pair already connected to
    the remote.
    """
    use_eip8 = False
    initiator = HandshakeInitiator(remote, privkey, use_eip8, token)
    reader, writer = await initiator.connect()
    opened_connections[remote.__repr__()] = (reader, writer)
    aes_secret, mac_secret, egress_mac, ingress_mac = await _handshake(
        initiator, reader, writer, token)
    return aes_secret, mac_secret, egress_mac, ingress_mac, reader, writer
示例#2
0
    async def connect(self, remote: Node) -> BasePeer:
        """
        Connect to the given remote and return a Peer instance when successful.
        Returns None if the remote is unreachable, times out or is useless.
        """
        if remote.pubkey == self.privkey.public_key:
            Logger.warning_every_n(
                "Skipping {} that has the same public key as local node, quite possible we are trying to connect to ourselves"
                .format(remote),
                100,
            )
            return None
        if remote in self.connected_nodes:
            self.logger.debug("Skipping %s; already connected to it", remote)
            return None
        if self.chk_dialout_blacklist(remote.address):
            Logger.warning_every_n(
                "failed to connect {} at least once, will not connect again; discovery should have removed it"
                .format(remote.address), 100)
            return None
        blacklistworthy_exceptions = (
            HandshakeFailure,  # after secure handshake handshake, when negotiating p2p command, eg. parsing hello failed; no matching p2p capabilities
            PeerConnectionLost,  # conn lost while reading
            TimeoutError,  # eg. read timeout (raised by CancelToken)
            UnreachablePeer,  # ConnectionRefusedError, OSError
        )
        expected_exceptions = (
            HandshakeDisconnectedFailure,  # during secure handshake, disconnected before getting ack; or got Disconnect cmd for some known reason
        )
        try:
            self.logger.debug("Connecting to %s...", remote)
            # We use self.wait() as well as passing our CancelToken to handshake() as a workaround
            # for https://github.com/ethereum/py-evm/issues/670.
            peer = await self.wait(handshake(remote, self.get_peer_factory()))

            return peer
        except OperationCancelled:
            # Pass it on to instruct our main loop to stop.
            raise
        except BadAckMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in our authentication code.
            Logger.error_every_n("Got bad auth ack from {}".format(remote),
                                 100)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got bad auth ack from %r",
                              remote,
                              exc_info=True)
            self.dialout_blacklist(remote.address)
        except MalformedMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in how we decode messages during handshake.
            Logger.error_every_n(
                "Got malformed response from {} during handshake".format(
                    remote), 100)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got malformed response from %r",
                              remote,
                              exc_info=True)
            self.dialout_blacklist(remote.address)
        except blacklistworthy_exceptions as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
            Logger.error_every_n(
                "Could not complete handshake with {}: {}".format(
                    repr(remote), repr(e)), 100)
            self.dialout_blacklist(remote.address)
        except expected_exceptions as e:
            self.logger.debug("Disconnected during handshake %r: %s", remote,
                              repr(e))
            Logger.error_every_n(
                "Disconnected during handshake {}: {}".format(
                    repr(remote), repr(e)), 100)
        except Exception:
            self.logger.exception(
                "Unexpected error during auth/p2p handshake with %r", remote)
            self.dialout_blacklist(remote.address)
        if remote.__repr__() in auth.opened_connections:
            reader, writer = auth.opened_connections[remote.__repr__()]
            reader.feed_eof()
            writer.close()
            Logger.error_every_n(
                "Closing connection to {}".format(remote.__repr__()), 100)
            del auth.opened_connections[remote.__repr__()]
        return None
示例#3
0
    async def connect(self, remote: Node) -> BasePeer:
        """
        Connect to the given remote and return a Peer instance when successful.
        Returns None if the remote is unreachable, times out or is useless.
        """
        if remote.pubkey == self.privkey.public_key:
            Logger.warning_every_n(
                "Skipping {} that has the same public key as local node, quite possible we are trying to connect to ourselves"
                .format(remote),
                100,
            )
            return None
        if remote in self.connected_nodes:
            self.logger.debug("Skipping %s; already connected to it", remote)
            return None
        expected_exceptions = (
            HandshakeFailure,
            PeerConnectionLost,
            TimeoutError,
            UnreachablePeer,
        )
        try:
            self.logger.debug("Connecting to %s...", remote)
            # We use self.wait() as well as passing our CancelToken to handshake() as a workaround
            # for https://github.com/ethereum/py-evm/issues/670.
            peer = await self.wait(handshake(remote, self.get_peer_factory()))

            return peer
        except OperationCancelled:
            # Pass it on to instruct our main loop to stop.
            raise
        except BadAckMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in our authentication code.
            self.logger.error("Got bad auth ack from %r", remote)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got bad auth ack from %r",
                              remote,
                              exc_info=True)
        except MalformedMessage:
            # This is kept separate from the `expected_exceptions` to be sure that we aren't
            # silencing an error in how we decode messages during handshake.
            self.logger.error(
                "Got malformed response from %r during handshake", remote)
            # dump the full stacktrace in the debug logs
            self.logger.debug("Got malformed response from %r",
                              remote,
                              exc_info=True)
        except expected_exceptions as e:
            self.logger.debug("Could not complete handshake with %r: %s",
                              remote, repr(e))
        except Exception:
            self.logger.exception(
                "Unexpected error during auth/p2p handshake with %r", remote)
        if remote.__repr__() in auth.opened_connections:
            reader, writer = auth.opened_connections[remote.__repr__()]
            reader.feed_eof()
            writer.close()
            self.logger.error("Closing connection to %r", remote.__repr__())
            del auth.opened_connections[remote.__repr__()]
        return None