2020-11-11 19:27:03 -07:00
|
|
|
use crate::{ip_echo_server_reply_length, HEADER_LENGTH};
|
2019-09-04 23:10:35 -07:00
|
|
|
use bytes::Bytes;
|
2019-05-03 11:01:35 -07:00
|
|
|
use log::*;
|
2019-09-04 23:10:35 -07:00
|
|
|
use serde_derive::{Deserialize, Serialize};
|
2020-04-27 16:54:11 -07:00
|
|
|
use std::{io, net::SocketAddr, time::Duration};
|
|
|
|
use tokio::{net::TcpListener, prelude::*, reactor::Handle, runtime::Runtime};
|
2019-09-04 23:10:35 -07:00
|
|
|
use tokio_codec::{BytesCodec, Decoder};
|
2019-05-03 11:01:35 -07:00
|
|
|
|
|
|
|
pub type IpEchoServer = Runtime;
|
|
|
|
|
2020-06-15 07:36:08 +09:00
|
|
|
pub const MAX_PORT_COUNT_PER_MESSAGE: usize = 4;
|
|
|
|
|
2019-09-04 23:10:35 -07:00
|
|
|
#[derive(Serialize, Deserialize, Default)]
|
|
|
|
pub(crate) struct IpEchoServerMessage {
|
2020-06-15 07:36:08 +09:00
|
|
|
tcp_ports: [u16; MAX_PORT_COUNT_PER_MESSAGE], // Fixed size list of ports to avoid vec serde
|
|
|
|
udp_ports: [u16; MAX_PORT_COUNT_PER_MESSAGE], // Fixed size list of ports to avoid vec serde
|
2019-09-04 23:10:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl IpEchoServerMessage {
|
|
|
|
pub fn new(tcp_ports: &[u16], udp_ports: &[u16]) -> Self {
|
|
|
|
let mut msg = Self::default();
|
|
|
|
assert!(tcp_ports.len() <= msg.tcp_ports.len());
|
|
|
|
assert!(udp_ports.len() <= msg.udp_ports.len());
|
|
|
|
|
|
|
|
msg.tcp_ports[..tcp_ports.len()].copy_from_slice(tcp_ports);
|
|
|
|
msg.udp_ports[..udp_ports.len()].copy_from_slice(udp_ports);
|
|
|
|
msg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 11:01:35 -07:00
|
|
|
/// Starts a simple TCP server on the given port that echos the IP address of any peer that
|
|
|
|
/// connects. Used by |get_public_ip_addr|
|
2019-09-19 17:16:22 -07:00
|
|
|
pub fn ip_echo_server(tcp: std::net::TcpListener) -> IpEchoServer {
|
|
|
|
info!("bound to {:?}", tcp.local_addr());
|
|
|
|
let tcp =
|
|
|
|
TcpListener::from_std(tcp, &Handle::default()).expect("Failed to convert std::TcpListener");
|
2019-05-03 11:01:35 -07:00
|
|
|
|
|
|
|
let server = tcp
|
|
|
|
.incoming()
|
|
|
|
.map_err(|err| warn!("accept failed: {:?}", err))
|
2020-01-04 11:00:22 -07:00
|
|
|
.filter_map(|socket| match socket.peer_addr() {
|
|
|
|
Ok(peer_addr) => {
|
|
|
|
info!("connection from {:?}", peer_addr);
|
|
|
|
Some((peer_addr, BytesCodec::new().framed(socket)))
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
info!("peer_addr failed for {:?}: {:?}", socket, err);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.for_each(move |(peer_addr, framed)| {
|
2019-09-04 23:10:35 -07:00
|
|
|
let (writer, reader) = framed.split();
|
|
|
|
|
|
|
|
let processor = reader
|
2019-12-02 10:01:25 -07:00
|
|
|
.and_then(move |data| {
|
2020-11-11 20:37:43 -07:00
|
|
|
if data.len() < HEADER_LENGTH {
|
2019-12-02 10:01:25 -07:00
|
|
|
return Err(io::Error::new(
|
2019-09-04 23:10:35 -07:00
|
|
|
io::ErrorKind::Other,
|
2019-12-02 10:01:25 -07:00
|
|
|
format!("Request too short, received {} bytes", data.len()),
|
|
|
|
));
|
|
|
|
}
|
2020-11-11 20:37:43 -07:00
|
|
|
let request_header: String =
|
|
|
|
data[0..HEADER_LENGTH].iter().map(|b| *b as char).collect();
|
2019-12-02 10:01:25 -07:00
|
|
|
if request_header != "\0\0\0\0" {
|
|
|
|
// Explicitly check for HTTP GET/POST requests to more gracefully handle
|
|
|
|
// the case where a user accidentally tried to use a gossip entrypoint in
|
|
|
|
// place of a JSON RPC URL:
|
|
|
|
if request_header == "GET " || request_header == "POST" {
|
|
|
|
return Ok(None); // None -> Send HTTP error response
|
|
|
|
}
|
|
|
|
return Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!("Bad request header: {}", request_header),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2019-12-02 23:32:43 -07:00
|
|
|
let expected_len =
|
|
|
|
bincode::serialized_size(&IpEchoServerMessage::default()).unwrap() as usize;
|
2020-11-11 20:37:43 -07:00
|
|
|
let actual_len = data[HEADER_LENGTH..].len();
|
2019-12-02 23:32:43 -07:00
|
|
|
if actual_len < expected_len {
|
|
|
|
return Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!(
|
|
|
|
"Request too short, actual {} < expected {}",
|
|
|
|
actual_len, expected_len
|
|
|
|
),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2020-11-11 20:37:43 -07:00
|
|
|
bincode::deserialize::<IpEchoServerMessage>(&data[HEADER_LENGTH..])
|
2019-12-02 10:01:25 -07:00
|
|
|
.map(Some)
|
2020-06-09 01:38:14 +01:00
|
|
|
.map_err(|err| {
|
|
|
|
io::Error::new(
|
2019-12-02 10:01:25 -07:00
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!("Failed to deserialize IpEchoServerMessage: {:?}", err),
|
2020-06-09 01:38:14 +01:00
|
|
|
)
|
2019-12-02 10:01:25 -07:00
|
|
|
})
|
2019-05-03 11:01:35 -07:00
|
|
|
})
|
2019-12-02 10:01:25 -07:00
|
|
|
.and_then(move |maybe_msg| {
|
|
|
|
match maybe_msg {
|
|
|
|
None => None, // Send HTTP error response
|
|
|
|
Some(msg) => {
|
|
|
|
// Fire a datagram at each non-zero UDP port
|
|
|
|
if !msg.udp_ports.is_empty() {
|
|
|
|
match std::net::UdpSocket::bind("0.0.0.0:0") {
|
|
|
|
Ok(udp_socket) => {
|
|
|
|
for udp_port in &msg.udp_ports {
|
|
|
|
if *udp_port != 0 {
|
|
|
|
match udp_socket.send_to(
|
|
|
|
&[0],
|
|
|
|
SocketAddr::from((peer_addr.ip(), *udp_port)),
|
|
|
|
) {
|
|
|
|
Ok(_) => debug!(
|
|
|
|
"Successful send_to udp/{}",
|
|
|
|
udp_port
|
|
|
|
),
|
|
|
|
Err(err) => info!(
|
|
|
|
"Failed to send_to udp/{}: {}",
|
|
|
|
udp_port, err
|
|
|
|
),
|
|
|
|
}
|
2019-09-04 23:10:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-02 10:01:25 -07:00
|
|
|
Err(err) => {
|
|
|
|
warn!("Failed to bind local udp socket: {}", err);
|
|
|
|
}
|
2019-09-04 23:10:35 -07:00
|
|
|
}
|
|
|
|
}
|
2019-12-02 10:01:25 -07:00
|
|
|
|
|
|
|
// Try to connect to each non-zero TCP port
|
|
|
|
let tcp_futures: Vec<_> =
|
|
|
|
msg.tcp_ports
|
|
|
|
.iter()
|
|
|
|
.filter_map(|tcp_port| {
|
|
|
|
let tcp_port = *tcp_port;
|
|
|
|
if tcp_port == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(
|
|
|
|
tokio::net::TcpStream::connect(&SocketAddr::new(
|
|
|
|
peer_addr.ip(),
|
|
|
|
tcp_port,
|
|
|
|
))
|
|
|
|
.and_then(move |tcp_stream| {
|
|
|
|
debug!(
|
|
|
|
"Connection established to tcp/{}",
|
|
|
|
tcp_port
|
|
|
|
);
|
|
|
|
let _ = tcp_stream
|
|
|
|
.shutdown(std::net::Shutdown::Both);
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
.timeout(Duration::from_secs(5))
|
|
|
|
.or_else(move |err| {
|
|
|
|
Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!(
|
|
|
|
"Connection timeout to {}: {:?}",
|
|
|
|
tcp_port, err
|
|
|
|
),
|
|
|
|
))
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
Some(future::join_all(tcp_futures))
|
2019-09-04 23:10:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2019-12-02 10:01:25 -07:00
|
|
|
.and_then(move |valid_request| {
|
|
|
|
if valid_request.is_none() {
|
|
|
|
Ok(Bytes::from(
|
|
|
|
"HTTP/1.1 400 Bad Request\nContent-length: 0\n\n",
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
// "\0\0\0\0" header is added to ensure a valid response will never
|
|
|
|
// conflict with the first four bytes of a valid HTTP response.
|
2020-11-11 19:27:03 -07:00
|
|
|
let mut bytes = vec![0u8; ip_echo_server_reply_length()];
|
2020-11-11 20:37:43 -07:00
|
|
|
bincode::serialize_into(&mut bytes[HEADER_LENGTH..], &peer_addr.ip())
|
|
|
|
.unwrap();
|
2019-12-02 10:01:25 -07:00
|
|
|
Ok(Bytes::from(bytes))
|
|
|
|
}
|
2019-09-04 23:10:35 -07:00
|
|
|
});
|
2019-05-03 11:01:35 -07:00
|
|
|
|
2019-09-04 23:10:35 -07:00
|
|
|
let connection = writer
|
|
|
|
.send_all(processor)
|
|
|
|
.timeout(Duration::from_secs(5))
|
|
|
|
.then(|result| {
|
|
|
|
if let Err(err) = result {
|
|
|
|
info!("Session failed: {:?}", err);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
});
|
2019-05-03 11:01:35 -07:00
|
|
|
|
2019-09-04 23:10:35 -07:00
|
|
|
tokio::spawn(connection)
|
2019-05-03 11:01:35 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
let mut rt = Runtime::new().expect("Failed to create Runtime");
|
|
|
|
rt.spawn(server);
|
|
|
|
rt
|
|
|
|
}
|