2022-01-14 11:34:59 -08:00
|
|
|
//! Creating isolated connections to specific peers.
|
2020-09-01 20:41:43 -07:00
|
|
|
|
2022-01-14 11:34:59 -08:00
|
|
|
use std::{future::Future, net::SocketAddr};
|
2020-09-01 20:41:43 -07:00
|
|
|
|
2022-01-14 11:34:59 -08:00
|
|
|
use futures::future::TryFutureExt;
|
|
|
|
use tokio::io::{AsyncRead, AsyncWrite};
|
2020-09-01 20:41:43 -07:00
|
|
|
use tower::{
|
|
|
|
util::{BoxService, Oneshot},
|
2022-01-14 11:34:59 -08:00
|
|
|
ServiceExt,
|
2020-09-01 20:41:43 -07:00
|
|
|
};
|
|
|
|
|
2022-01-14 11:34:59 -08:00
|
|
|
use zebra_chain::{chain_tip::NoChainTip, parameters::Network};
|
2021-08-26 18:34:33 -07:00
|
|
|
|
|
|
|
use crate::{
|
2021-10-21 14:36:42 -07:00
|
|
|
peer::{self, ConnectedAddr, HandshakeRequest},
|
|
|
|
peer_set::ActiveConnectionCounter,
|
2021-08-26 18:34:33 -07:00
|
|
|
BoxError, Config, Request, Response,
|
|
|
|
};
|
2020-09-01 20:41:43 -07:00
|
|
|
|
2022-01-14 11:34:59 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
/// Creates a Zcash peer connection using the provided data stream.
|
|
|
|
/// This connection is completely isolated from all other node state.
|
2020-09-01 20:41:43 -07:00
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// The connection pool returned by [`init`](zebra_network::init)
|
|
|
|
/// should be used for all requests that
|
2020-09-01 20:41:43 -07:00
|
|
|
/// don't require isolated state or use of an existing TCP connection. However,
|
|
|
|
/// this low-level API is useful for custom network crawlers or Tor connections.
|
|
|
|
///
|
|
|
|
/// In addition to being completely isolated from all other node state, this
|
|
|
|
/// method also aims to be minimally distinguishable from other clients.
|
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// SECURITY TODO: check if the timestamp field can be zeroed, to remove another distinguisher (#3300)
|
|
|
|
///
|
2020-09-01 20:41:43 -07:00
|
|
|
/// Note that this method does not implement any timeout behavior, so callers may
|
|
|
|
/// want to layer it with a timeout as appropriate for their application.
|
|
|
|
///
|
|
|
|
/// # Inputs
|
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// - `network`: the Zcash [`Network`] used for this connection.
|
2020-09-01 20:41:43 -07:00
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// - `data_stream`: an existing data stream. This can be a non-anonymised TCP connection,
|
|
|
|
/// or a Tor client [`DataStream`].
|
2021-02-04 14:11:21 -08:00
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// - `user_agent`: a valid BIP14 user-agent, e.g., the empty string.
|
|
|
|
pub fn connect_isolated<AsyncReadWrite>(
|
|
|
|
network: Network,
|
|
|
|
data_stream: AsyncReadWrite,
|
2020-09-01 20:41:43 -07:00
|
|
|
user_agent: String,
|
2022-01-14 11:34:59 -08:00
|
|
|
) -> impl Future<Output = Result<BoxService<Request, Response, BoxError>, BoxError>>
|
|
|
|
where
|
|
|
|
AsyncReadWrite: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
|
|
|
{
|
|
|
|
let config = Config {
|
|
|
|
network,
|
|
|
|
..Config::default()
|
|
|
|
};
|
|
|
|
|
2020-09-01 20:41:43 -07:00
|
|
|
let handshake = peer::Handshake::builder()
|
2022-01-14 11:34:59 -08:00
|
|
|
.with_config(config)
|
2020-09-01 20:41:43 -07:00
|
|
|
.with_inbound_service(tower::service_fn(|_req| async move {
|
2022-01-14 11:34:59 -08:00
|
|
|
Ok::<Response, BoxError>(Response::Nil)
|
2020-09-01 20:41:43 -07:00
|
|
|
}))
|
|
|
|
.with_user_agent(user_agent)
|
2021-09-01 15:31:16 -07:00
|
|
|
.with_latest_chain_tip(NoChainTip)
|
2020-09-01 20:41:43 -07:00
|
|
|
.finish()
|
|
|
|
.expect("provided mandatory builder parameters");
|
|
|
|
|
2021-10-21 14:36:42 -07:00
|
|
|
// Don't send or track any metadata about the connection
|
2021-05-06 17:50:04 -07:00
|
|
|
let connected_addr = ConnectedAddr::new_isolated();
|
2021-10-21 14:36:42 -07:00
|
|
|
let connection_tracker = ActiveConnectionCounter::new_counter().track_connection();
|
2020-09-01 20:41:43 -07:00
|
|
|
|
2021-10-21 14:36:42 -07:00
|
|
|
Oneshot::new(
|
|
|
|
handshake,
|
|
|
|
HandshakeRequest {
|
2022-01-14 11:34:59 -08:00
|
|
|
data_stream,
|
2021-10-21 14:36:42 -07:00
|
|
|
connected_addr,
|
|
|
|
connection_tracker,
|
|
|
|
},
|
|
|
|
)
|
2022-01-14 11:34:59 -08:00
|
|
|
.map_ok(|client| BoxService::new(client.map_err(Into::into)))
|
2020-09-01 20:41:43 -07:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:34:59 -08:00
|
|
|
/// Creates a direct TCP Zcash peer connection to `addr`.
|
|
|
|
/// This connection is completely isolated from all other node state.
|
|
|
|
///
|
|
|
|
/// See [`connect_isolated`] for details.
|
|
|
|
///
|
|
|
|
/// # Privacy
|
|
|
|
///
|
|
|
|
/// Transactions sent over this connection can be linked to the sending and receiving IP address
|
|
|
|
/// by passive internet observers.
|
|
|
|
pub fn connect_isolated_tcp_direct(
|
|
|
|
network: Network,
|
|
|
|
addr: SocketAddr,
|
|
|
|
user_agent: String,
|
|
|
|
) -> impl Future<Output = Result<BoxService<Request, Response, BoxError>, BoxError>> {
|
|
|
|
tokio::net::TcpStream::connect(addr)
|
|
|
|
.err_into()
|
|
|
|
.and_then(move |tcp_stream| connect_isolated(network, tcp_stream, user_agent))
|
2020-09-14 12:47:07 -07:00
|
|
|
}
|