2016-10-26 08:06:13 +03:00
|
|
|
// Copyright 2016 The Grin Developers
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
use std::collections::VecDeque;
|
2017-02-19 05:42:34 +03:00
|
|
|
use std::net::SocketAddr;
|
2016-12-11 06:11:49 +03:00
|
|
|
use std::sync::{Arc, RwLock};
|
2016-10-26 08:06:13 +03:00
|
|
|
|
2016-12-11 06:11:49 +03:00
|
|
|
use futures::Future;
|
2016-10-26 08:06:13 +03:00
|
|
|
use rand::Rng;
|
|
|
|
use rand::os::OsRng;
|
2016-12-11 06:11:49 +03:00
|
|
|
use tokio_core::net::TcpStream;
|
2016-10-26 08:06:13 +03:00
|
|
|
|
2017-02-08 00:52:17 +03:00
|
|
|
use core::core::target::Difficulty;
|
2017-02-27 07:08:40 +03:00
|
|
|
use core::ser;
|
2016-10-26 08:06:13 +03:00
|
|
|
use msg::*;
|
|
|
|
use types::*;
|
|
|
|
use protocol::ProtocolV1;
|
2017-10-12 19:56:44 +03:00
|
|
|
use util::LOGGER;
|
2016-10-26 08:06:13 +03:00
|
|
|
|
|
|
|
const NONCES_CAP: usize = 100;
|
|
|
|
|
|
|
|
/// Handles the handshake negotiation when two peers connect and decides on
|
|
|
|
/// protocol.
|
|
|
|
pub struct Handshake {
|
|
|
|
/// Ring buffer of nonces sent to detect self connections without requiring
|
|
|
|
/// a node id.
|
2016-12-11 06:11:49 +03:00
|
|
|
nonces: Arc<RwLock<VecDeque<u64>>>,
|
2016-10-26 08:06:13 +03:00
|
|
|
}
|
|
|
|
|
2016-10-28 00:28:02 +03:00
|
|
|
unsafe impl Sync for Handshake {}
|
|
|
|
unsafe impl Send for Handshake {}
|
2016-10-26 08:06:13 +03:00
|
|
|
|
|
|
|
impl Handshake {
|
|
|
|
/// Creates a new handshake handler
|
|
|
|
pub fn new() -> Handshake {
|
2017-11-01 02:32:33 +03:00
|
|
|
Handshake {
|
|
|
|
nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))),
|
|
|
|
}
|
2016-10-26 08:06:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles connecting to a new remote peer, starting the version handshake.
|
2017-10-26 20:48:51 +03:00
|
|
|
pub fn connect(
|
|
|
|
&self,
|
|
|
|
capab: Capabilities,
|
|
|
|
total_difficulty: Difficulty,
|
|
|
|
self_addr: SocketAddr,
|
|
|
|
conn: TcpStream,
|
|
|
|
) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
|
2016-12-12 00:04:52 +03:00
|
|
|
// prepare the first part of the hanshake
|
2016-10-26 08:06:13 +03:00
|
|
|
let nonce = self.next_nonce();
|
2016-12-11 06:11:49 +03:00
|
|
|
let hand = Hand {
|
|
|
|
version: PROTOCOL_VERSION,
|
2017-02-19 05:42:34 +03:00
|
|
|
capabilities: capab,
|
2016-12-11 06:11:49 +03:00
|
|
|
nonce: nonce,
|
2017-02-08 00:52:17 +03:00
|
|
|
total_difficulty: total_difficulty,
|
2017-02-19 05:42:34 +03:00
|
|
|
sender_addr: SockAddr(self_addr),
|
2016-12-11 06:11:49 +03:00
|
|
|
receiver_addr: SockAddr(conn.peer_addr().unwrap()),
|
|
|
|
user_agent: USER_AGENT.to_string(),
|
2016-10-31 04:23:52 +03:00
|
|
|
};
|
2016-12-12 00:04:52 +03:00
|
|
|
|
|
|
|
// write and read the handshake response
|
2017-09-29 21:44:25 +03:00
|
|
|
Box::new(
|
|
|
|
write_msg(conn, hand, Type::Hand)
|
|
|
|
.and_then(|conn| read_msg::<Shake>(conn))
|
|
|
|
.and_then(|(conn, shake)| {
|
|
|
|
if shake.version != 1 {
|
|
|
|
Err(Error::Serialization(ser::Error::UnexpectedData {
|
|
|
|
expected: vec![PROTOCOL_VERSION as u8],
|
|
|
|
received: vec![shake.version as u8],
|
|
|
|
}))
|
|
|
|
} else {
|
|
|
|
let peer_info = PeerInfo {
|
|
|
|
capabilities: shake.capabilities,
|
|
|
|
user_agent: shake.user_agent,
|
|
|
|
addr: conn.peer_addr().unwrap(),
|
|
|
|
version: shake.version,
|
|
|
|
total_difficulty: shake.total_difficulty,
|
|
|
|
};
|
2016-12-11 06:11:49 +03:00
|
|
|
|
2017-10-12 19:56:44 +03:00
|
|
|
info!(LOGGER, "Connected to peer {:?}", peer_info);
|
2017-09-29 21:44:25 +03:00
|
|
|
// when more than one protocol version is supported, choosing should go here
|
|
|
|
Ok((conn, ProtocolV1::new(), peer_info))
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
)
|
2016-10-26 08:06:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles receiving a connection from a new remote peer that started the
|
|
|
|
/// version handshake.
|
2017-10-26 20:48:51 +03:00
|
|
|
pub fn handshake(
|
|
|
|
&self,
|
|
|
|
capab: Capabilities,
|
|
|
|
total_difficulty: Difficulty,
|
|
|
|
conn: TcpStream,
|
|
|
|
) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
|
2016-12-11 06:11:49 +03:00
|
|
|
let nonces = self.nonces.clone();
|
2017-09-29 21:44:25 +03:00
|
|
|
Box::new(
|
|
|
|
read_msg::<Hand>(conn)
|
|
|
|
.and_then(move |(conn, hand)| {
|
|
|
|
if hand.version != 1 {
|
2017-02-27 07:08:40 +03:00
|
|
|
return Err(Error::Serialization(ser::Error::UnexpectedData {
|
2017-09-29 21:44:25 +03:00
|
|
|
expected: vec![PROTOCOL_VERSION as u8],
|
|
|
|
received: vec![hand.version as u8],
|
2017-02-27 07:08:40 +03:00
|
|
|
}));
|
2016-12-11 06:11:49 +03:00
|
|
|
}
|
2017-09-29 21:44:25 +03:00
|
|
|
{
|
|
|
|
// check the nonce to see if we could be trying to connect to ourselves
|
|
|
|
let nonces = nonces.read().unwrap();
|
|
|
|
if nonces.contains(&hand.nonce) {
|
|
|
|
return Err(Error::Serialization(ser::Error::UnexpectedData {
|
|
|
|
expected: vec![],
|
|
|
|
received: vec![],
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2017-11-02 01:56:59 +03:00
|
|
|
|
2017-09-29 21:44:25 +03:00
|
|
|
// all good, keep peer info
|
|
|
|
let peer_info = PeerInfo {
|
|
|
|
capabilities: hand.capabilities,
|
|
|
|
user_agent: hand.user_agent,
|
2017-11-02 01:56:59 +03:00
|
|
|
addr: extract_ip(&hand.sender_addr.0, &conn),
|
2017-09-29 21:44:25 +03:00
|
|
|
version: hand.version,
|
|
|
|
total_difficulty: hand.total_difficulty,
|
|
|
|
};
|
|
|
|
// send our reply with our info
|
|
|
|
let shake = Shake {
|
|
|
|
version: PROTOCOL_VERSION,
|
|
|
|
capabilities: capab,
|
|
|
|
total_difficulty: total_difficulty,
|
|
|
|
user_agent: USER_AGENT.to_string(),
|
|
|
|
};
|
|
|
|
Ok((conn, shake, peer_info))
|
|
|
|
})
|
|
|
|
.and_then(|(conn, shake, peer_info)| {
|
2017-10-12 19:56:44 +03:00
|
|
|
debug!(LOGGER, "Success handshake with {}.", peer_info.addr);
|
2017-09-29 21:44:25 +03:00
|
|
|
write_msg(conn, shake, Type::Shake)
|
2016-12-11 06:11:49 +03:00
|
|
|
// when more than one protocol version is supported, choosing should go here
|
|
|
|
.map(|conn| (conn, ProtocolV1::new(), peer_info))
|
2017-09-29 21:44:25 +03:00
|
|
|
}),
|
|
|
|
)
|
2016-10-31 04:23:52 +03:00
|
|
|
}
|
2016-10-26 08:06:13 +03:00
|
|
|
|
2016-10-28 00:28:02 +03:00
|
|
|
/// Generate a new random nonce and store it in our ring buffer
|
2016-10-26 08:06:13 +03:00
|
|
|
fn next_nonce(&self) -> u64 {
|
|
|
|
let mut rng = OsRng::new().unwrap();
|
|
|
|
let nonce = rng.next_u64();
|
|
|
|
|
|
|
|
let mut nonces = self.nonces.write().unwrap();
|
|
|
|
nonces.push_back(nonce);
|
|
|
|
if nonces.len() >= NONCES_CAP {
|
|
|
|
nonces.pop_front();
|
|
|
|
}
|
|
|
|
nonce
|
|
|
|
}
|
|
|
|
}
|
2017-11-02 01:56:59 +03:00
|
|
|
|
|
|
|
// Attempts to make a best guess at the correct remote IP by checking if the
|
|
|
|
// advertised address is the loopback and our TCP connection. Note that the
|
|
|
|
// port reported by the connection is always incorrect for receiving
|
|
|
|
// connections as it's dynamically allocated by the server.
|
|
|
|
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
|
|
|
|
match advertised {
|
|
|
|
&SocketAddr::V4(v4sock) => {
|
2017-11-03 23:47:35 +03:00
|
|
|
let ip = v4sock.ip();
|
|
|
|
if ip.is_loopback() || ip.is_unspecified() {
|
2017-11-02 01:56:59 +03:00
|
|
|
if let Ok(addr) = conn.peer_addr() {
|
|
|
|
return SocketAddr::new(addr.ip(), advertised.port());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&SocketAddr::V6(v6sock) => {
|
2017-11-03 23:47:35 +03:00
|
|
|
let ip = v6sock.ip();
|
|
|
|
if ip.is_loopback() || ip.is_unspecified() {
|
2017-11-02 01:56:59 +03:00
|
|
|
if let Ok(addr) = conn.peer_addr() {
|
|
|
|
return SocketAddr::new(addr.ip(), advertised.port());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
advertised.clone()
|
|
|
|
}
|