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
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
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