|
@ -36,66 +36,89 @@ namespace dev |
|
|
namespace p2p |
|
|
namespace p2p |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief Setup inbound or outbound connection for communication over RLPXFrameIO. |
|
|
|
|
|
* RLPx Spec: https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake
|
|
|
|
|
|
* |
|
|
|
|
|
* @todo Implement StartSession transition via lambda which is passed to constructor. |
|
|
|
|
|
* |
|
|
|
|
|
* Thread Safety |
|
|
|
|
|
* Distinct Objects: Safe. |
|
|
|
|
|
* Shared objects: Unsafe. |
|
|
|
|
|
*/ |
|
|
class RLPXHandshake: public std::enable_shared_from_this<RLPXHandshake> |
|
|
class RLPXHandshake: public std::enable_shared_from_this<RLPXHandshake> |
|
|
{ |
|
|
{ |
|
|
friend class RLPXFrameIO; |
|
|
friend class RLPXFrameIO; |
|
|
|
|
|
|
|
|
|
|
|
/// Sequential states of handshake
|
|
|
enum State |
|
|
enum State |
|
|
{ |
|
|
{ |
|
|
Error = -1, |
|
|
Error = -1, |
|
|
New, // New->AckAuth [egress: tx auth, ingress: rx auth]
|
|
|
New, |
|
|
AckAuth, // AckAuth->WriteHello [egress: rx ack, ingress: tx ack]
|
|
|
AckAuth, |
|
|
WriteHello, // WriteHello [tx caps, rx caps, writehello]
|
|
|
WriteHello, |
|
|
ReadHello, |
|
|
ReadHello, |
|
|
StartSession |
|
|
StartSession |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
/// Handshake for ingress connection. Takes ownership of socket.
|
|
|
/// Setup incoming connection.
|
|
|
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket): m_host(_host), m_originated(false), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } |
|
|
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket): m_host(_host), m_originated(false), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } |
|
|
|
|
|
|
|
|
/// Handshake for egress connection to _remote. Takes ownership of socket.
|
|
|
/// Setup outbound connection.
|
|
|
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket, NodeId _remote): m_host(_host), m_remote(_remote), m_originated(true), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } |
|
|
RLPXHandshake(Host* _host, std::shared_ptr<RLPXSocket> const& _socket, NodeId _remote): m_host(_host), m_remote(_remote), m_originated(true), m_socket(_socket) { crypto::Nonce::get().ref().copyTo(m_nonce.ref()); } |
|
|
|
|
|
|
|
|
~RLPXHandshake() {} |
|
|
~RLPXHandshake() {} |
|
|
|
|
|
|
|
|
|
|
|
/// Start handshake.
|
|
|
void start() { transition(); } |
|
|
void start() { transition(); } |
|
|
|
|
|
|
|
|
protected: |
|
|
protected: |
|
|
|
|
|
/// Write Auth message to socket and transitions to AckAuth.
|
|
|
void writeAuth(); |
|
|
void writeAuth(); |
|
|
|
|
|
|
|
|
|
|
|
/// Reads Auth message from socket and transitions to AckAuth.
|
|
|
void readAuth(); |
|
|
void readAuth(); |
|
|
|
|
|
|
|
|
|
|
|
/// Write Ack message to socket and transitions to WriteHello.
|
|
|
void writeAck(); |
|
|
void writeAck(); |
|
|
|
|
|
|
|
|
|
|
|
/// Reads Auth message from socket and transitions to WriteHello.
|
|
|
void readAck(); |
|
|
void readAck(); |
|
|
|
|
|
|
|
|
|
|
|
/// Closes connection and ends transitions.
|
|
|
void error(); |
|
|
void error(); |
|
|
|
|
|
|
|
|
|
|
|
/// Performs transition for m_nextState.
|
|
|
void transition(boost::system::error_code _ech = boost::system::error_code()); |
|
|
void transition(boost::system::error_code _ech = boost::system::error_code()); |
|
|
|
|
|
|
|
|
/// Current state of handshake.
|
|
|
State m_nextState = New; ///< Current or expected state of transition.
|
|
|
State m_nextState = New; |
|
|
|
|
|
|
|
|
|
|
|
Host* m_host; |
|
|
Host* m_host; ///< Host which provides m_alias, protocolVersion(), m_clientVersion, caps(), and TCP listenPort().
|
|
|
|
|
|
|
|
|
/// Node id of remote host for socket.
|
|
|
/// Node id of remote host for socket.
|
|
|
NodeId m_remote; |
|
|
NodeId m_remote; ///< Public address of remote host.
|
|
|
bool m_originated = false; |
|
|
bool m_originated = false; ///< True if connection is outbound.
|
|
|
|
|
|
|
|
|
/// Buffers for encoded and decoded handshake phases
|
|
|
/// Buffers for encoded and decoded handshake phases
|
|
|
bytes m_auth; |
|
|
bytes m_auth; ///< Plaintext of egress or ingress Auth message.
|
|
|
bytes m_authCipher; |
|
|
bytes m_authCipher; ///< Ciphertext of egress or ingress Auth message.
|
|
|
bytes m_ack; |
|
|
bytes m_ack; ///< Plaintext of egress or ingress Ack message.
|
|
|
bytes m_ackCipher; |
|
|
bytes m_ackCipher; ///< Ciphertext of egress or ingress Ack message.
|
|
|
bytes m_handshakeOutBuffer; |
|
|
bytes m_handshakeOutBuffer; ///< Frame buffer for egress Hello packet.
|
|
|
bytes m_handshakeInBuffer; |
|
|
bytes m_handshakeInBuffer; ///< Frame buffer for ingress Hello packet.
|
|
|
|
|
|
|
|
|
crypto::ECDHE m_ecdhe; |
|
|
crypto::ECDHE m_ecdhe; ///< Ephemeral ECDH secret and agreement.
|
|
|
h256 m_nonce; |
|
|
h256 m_nonce; ///< Nonce generated by this host for handshake.
|
|
|
|
|
|
|
|
|
Public m_remoteEphemeral; |
|
|
Public m_remoteEphemeral; ///< Remote ephemeral public key.
|
|
|
h256 m_remoteNonce; |
|
|
h256 m_remoteNonce; ///< Nonce generated by remote host for handshake.
|
|
|
|
|
|
|
|
|
/// Frame IO is used to read frame for last step of handshake authentication.
|
|
|
/// Used to read and write RLPx encrypted frames for last step of handshake authentication.
|
|
|
RLPXFrameIO* m_io; |
|
|
/// Passed onto Host which will take ownership.
|
|
|
std::shared_ptr<RLPXSocket> m_socket; |
|
|
RLPXFrameIO* m_io = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<RLPXSocket> m_socket; ///< Socket.
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|