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-02-14 17:44:33 -08:00
|
|
|
Service, 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-24 17:46:31 -08:00
|
|
|
#[cfg(feature = "tor")]
|
|
|
|
pub(crate) mod tor;
|
|
|
|
|
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-06-13 18:22:16 -07:00
|
|
|
/// The connection pool returned by [`init`](crate::init)
|
2022-01-14 11:34:59 -08:00
|
|
|
/// 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
|
2022-02-14 17:44:33 -08:00
|
|
|
/// function also aims to be minimally distinguishable from other clients.
|
2020-09-01 20:41:43 -07:00
|
|
|
///
|
2022-01-14 11:34:59 -08:00
|
|
|
/// SECURITY TODO: check if the timestamp field can be zeroed, to remove another distinguisher (#3300)
|
|
|
|
///
|
2022-02-14 17:44:33 -08:00
|
|
|
/// Note that this function does not implement any timeout behavior, so callers may
|
2020-09-01 20:41:43 -07:00
|
|
|
/// 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,
|
2022-06-13 18:22:16 -07:00
|
|
|
/// or a Tor client `arti_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.
|
2022-01-24 17:46:31 -08:00
|
|
|
pub fn connect_isolated<PeerTransport>(
|
2022-01-14 11:34:59 -08:00
|
|
|
network: Network,
|
2022-01-24 17:46:31 -08:00
|
|
|
data_stream: PeerTransport,
|
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
|
2022-01-24 17:46:31 -08:00
|
|
|
PeerTransport: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
2022-02-14 17:44:33 -08:00
|
|
|
{
|
|
|
|
let nil_inbound_service =
|
|
|
|
tower::service_fn(|_req| async move { Ok::<Response, BoxError>(Response::Nil) });
|
|
|
|
|
|
|
|
connect_isolated_with_inbound(network, data_stream, user_agent, nil_inbound_service)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates an isolated Zcash peer connection using the provided data stream.
|
|
|
|
/// This function is for testing purposes only.
|
|
|
|
///
|
|
|
|
/// See [`connect_isolated`] for details.
|
|
|
|
///
|
|
|
|
/// # Additional Inputs
|
|
|
|
///
|
|
|
|
/// - `inbound_service`: a [`tower::Service`] that answers inbound requests from the connected peer.
|
|
|
|
///
|
|
|
|
/// # Privacy
|
|
|
|
///
|
|
|
|
/// This function can make the isolated connection send different responses to peers,
|
|
|
|
/// which makes it stand out from other isolated connections from other peers.
|
|
|
|
pub fn connect_isolated_with_inbound<PeerTransport, InboundService>(
|
|
|
|
network: Network,
|
|
|
|
data_stream: PeerTransport,
|
|
|
|
user_agent: String,
|
|
|
|
inbound_service: InboundService,
|
|
|
|
) -> impl Future<Output = Result<BoxService<Request, Response, BoxError>, BoxError>>
|
|
|
|
where
|
|
|
|
PeerTransport: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
|
|
|
InboundService:
|
|
|
|
Service<Request, Response = Response, Error = BoxError> + Clone + Send + 'static,
|
|
|
|
InboundService::Future: Send,
|
2022-01-14 11:34:59 -08:00
|
|
|
{
|
|
|
|
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)
|
2022-02-14 17:44:33 -08:00
|
|
|
.with_inbound_service(inbound_service)
|
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.
|
2022-01-24 17:46:31 -08:00
|
|
|
///
|
2022-06-13 18:22:16 -07:00
|
|
|
/// Prefer [`connect_isolated_tor`](tor::connect_isolated_tor) if available.
|
2022-01-14 11:34:59 -08:00
|
|
|
pub fn connect_isolated_tcp_direct(
|
|
|
|
network: Network,
|
|
|
|
addr: SocketAddr,
|
|
|
|
user_agent: String,
|
|
|
|
) -> impl Future<Output = Result<BoxService<Request, Response, BoxError>, BoxError>> {
|
2022-02-14 17:44:33 -08:00
|
|
|
let nil_inbound_service =
|
|
|
|
tower::service_fn(|_req| async move { Ok::<Response, BoxError>(Response::Nil) });
|
|
|
|
|
|
|
|
connect_isolated_tcp_direct_with_inbound(network, addr, user_agent, nil_inbound_service)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates an isolated Zcash peer connection using the provided data stream.
|
|
|
|
/// This function is for testing purposes only.
|
|
|
|
///
|
|
|
|
/// See [`connect_isolated_with_inbound`] and [`connect_isolated_tcp_direct`] for details.
|
|
|
|
///
|
|
|
|
/// # Privacy
|
|
|
|
///
|
|
|
|
/// This function can make the isolated connection send different responses to peers,
|
|
|
|
/// which makes it stand out from other isolated connections from other peers.
|
|
|
|
pub fn connect_isolated_tcp_direct_with_inbound<InboundService>(
|
|
|
|
network: Network,
|
|
|
|
addr: SocketAddr,
|
|
|
|
user_agent: String,
|
|
|
|
inbound_service: InboundService,
|
|
|
|
) -> impl Future<Output = Result<BoxService<Request, Response, BoxError>, BoxError>>
|
|
|
|
where
|
|
|
|
InboundService:
|
|
|
|
Service<Request, Response = Response, Error = BoxError> + Clone + Send + 'static,
|
|
|
|
InboundService::Future: Send,
|
|
|
|
{
|
2022-01-14 11:34:59 -08:00
|
|
|
tokio::net::TcpStream::connect(addr)
|
|
|
|
.err_into()
|
2022-02-14 17:44:33 -08:00
|
|
|
.and_then(move |tcp_stream| {
|
|
|
|
connect_isolated_with_inbound(network, tcp_stream, user_agent, inbound_service)
|
|
|
|
})
|
2020-09-14 12:47:07 -07:00
|
|
|
}
|