Example #1
0
async def _handshake(
    initiator: "HandshakeInitiator",
    reader: asyncio.StreamReader,
    writer: asyncio.StreamWriter,
    token: CancelToken,
) -> Tuple[bytes, bytes, keccak_256, keccak_256]:
    """See the handshake() function above.

    This code was factored out into this helper so that we can create Peers with directly
    connected readers/writers for our tests.
    """
    initiator_nonce = keccak(os.urandom(HASH_LEN))
    auth_msg = initiator.create_auth_message(initiator_nonce)
    auth_init = initiator.encrypt_auth_message(auth_msg)
    writer.write(auth_init)

    auth_ack = await token.cancellable_wait(
        reader.read(ENCRYPTED_AUTH_ACK_LEN), timeout=REPLY_TIMEOUT)

    if reader.at_eof():
        # This is what happens when Parity nodes have blacklisted us
        # (https://github.com/ethereum/py-evm/issues/901).
        raise HandshakeFailure("%s disconnected before sending auth ack",
                               repr(initiator.remote))

    ephemeral_pubkey, responder_nonce = initiator.decode_auth_ack_message(
        auth_ack)
    aes_secret, mac_secret, egress_mac, ingress_mac = initiator.derive_secrets(
        initiator_nonce, responder_nonce, ephemeral_pubkey, auth_init,
        auth_ack)

    return aes_secret, mac_secret, egress_mac, ingress_mac
async def handshake_for_version(remote: Node, factory):
    """Perform the auth and P2P handshakes (without sub-protocol handshake) with the given remote.
    Disconnect after initial hello message exchange, and return version id
    """
    try:
        (
            aes_secret,
            mac_secret,
            egress_mac,
            ingress_mac,
            reader,
            writer,
        ) = await auth.handshake(remote, factory.privkey, factory.cancel_token)
    except (ConnectionRefusedError, OSError) as e:
        raise UnreachablePeer() from e
    connection = PeerConnection(
        reader=reader,
        writer=writer,
        aes_secret=aes_secret,
        mac_secret=mac_secret,
        egress_mac=egress_mac,
        ingress_mac=ingress_mac,
    )
    peer = factory.create_peer(remote=remote, connection=connection, inbound=False)
    # see await peer.do_p2p_handshake()
    peer.base_protocol.send_handshake()
    try:
        cmd, msg = await peer.read_msg(timeout=peer.conn_idle_timeout)
    except rlp.DecodingError:
        raise HandshakeFailure("Got invalid rlp data during handshake")
    except MalformedMessage as e:
        raise HandshakeFailure("Got malformed message during handshake") from e
    if isinstance(cmd, Disconnect):
        msg = cast(Dict[str, Any], msg)
        raise HandshakeDisconnectedFailure(
            "disconnected before completing sub-proto handshake: {}".format(
                msg["reason_name"]
            )
        )
    msg = cast(Dict[str, Any], msg)
    if not isinstance(cmd, Hello):
        await peer.disconnect(DisconnectReason.bad_protocol)
        raise HandshakeFailure(
            "Expected a Hello msg, got {}, disconnecting".format(cmd)
        )
    return msg["client_version_string"]
Example #3
0
 async def do_sub_proto_handshake(self) -> None:
     """ overrides BasePeer.do_sub_proto_handshake()
     """
     self.secure_peer = SecurePeer(self)
     Logger.info("starting peer hello exchange")
     start_state = await self.secure_peer.start()
     if start_state:
         # returns None if successful
         raise HandshakeFailure(
             "hello message exchange failed: {}".format(start_state))
Example #4
0
 async def process_p2p_handshake(self, cmd: protocol.Command,
                                 msg: protocol.PayloadType) -> None:
     msg = cast(Dict[str, Any], msg)
     if not isinstance(cmd, Hello):
         await self.disconnect(DisconnectReason.bad_protocol)
         raise HandshakeFailure(
             f"Expected a Hello msg, got {cmd}, disconnecting")
     remote_capabilities = msg["capabilities"]
     try:
         self.sub_proto = self.select_sub_protocol(remote_capabilities)
     except NoMatchingPeerCapabilities:
         await self.disconnect(DisconnectReason.useless_peer)
         raise HandshakeFailure(
             f"No matching capabilities between us ({self.capabilities}) and {self.remote} "
             f"({remote_capabilities}), disconnecting")
     self.logger.debug(
         "Finished P2P handshake with %s, using sub-protocol %s",
         self.remote,
         self.sub_proto,
     )
Example #5
0
    async def do_p2p_handshake(self) -> None:
        """Perform the handshake for the P2P base protocol.

        Raises HandshakeFailure if the handshake is not successful.
        """
        self.base_protocol.send_handshake()

        try:
            cmd, msg = await self.read_msg()
        except rlp.DecodingError:
            raise HandshakeFailure("Got invalid rlp data during handshake")
        except MalformedMessage as e:
            raise HandshakeFailure(
                "Got malformed message during handshake") from e

        if isinstance(cmd, Disconnect):
            msg = cast(Dict[str, Any], msg)
            # Peers sometimes send a disconnect msg before they send the initial P2P handshake.
            raise HandshakeFailure(
                f"{self} disconnected before completing sub-proto handshake: {msg['reason_name']}"
            )
        await self.process_p2p_handshake(cmd, msg)
Example #6
0
    async def do_sub_proto_handshake(self) -> None:
        """Perform the handshake for the sub-protocol agreed with the remote peer.

        Raises HandshakeFailure if the handshake is not successful.
        """
        await self.send_sub_proto_handshake()
        cmd, msg = await self.read_msg()
        if isinstance(cmd, Ping):
            # Parity sends a Ping before the sub-proto handshake, so respond to that and read the
            # next one, which hopefully will be the actual handshake.
            self.base_protocol.send_pong()
            cmd, msg = await self.read_msg()
        if isinstance(cmd, Disconnect):
            msg = cast(Dict[str, Any], msg)
            # Peers sometimes send a disconnect msg before they send the sub-proto handshake.
            raise HandshakeFailure(
                f"{self} disconnected before completing sub-proto handshake: {msg['reason_name']}"
            )
        await self.process_sub_proto_handshake(cmd, msg)
        self.logger.debug("Finished %s handshake with %s", self.sub_proto,
                          self.remote)