-
Notifications
You must be signed in to change notification settings - Fork 128
Add Tor support for outbound connections via SOCKS #778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -192,6 +192,13 @@ pub struct Config { | |
| /// **Note:** If unset, default parameters will be used, and you will be able to override the | ||
| /// parameters on a per-payment basis in the corresponding method calls. | ||
| pub route_parameters: Option<RouteParametersConfig>, | ||
| /// Configuration options for enabling peer connections via the Tor network. | ||
| /// | ||
| /// Setting [`TorConfig`] enables connecting to Tor-only peers. Please refer to [`TorConfig`] | ||
| /// for further information. | ||
| /// | ||
| /// **Note**: If unset, connecting to peer OnionV3 addresses will fail. | ||
| pub tor_config: Option<TorConfig>, | ||
| } | ||
|
|
||
| impl Default for Config { | ||
|
|
@@ -204,6 +211,7 @@ impl Default for Config { | |
| trusted_peers_0conf: Vec::new(), | ||
| probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER, | ||
| anchor_channels_config: Some(AnchorChannelsConfig::default()), | ||
| tor_config: None, | ||
| route_parameters: None, | ||
| node_alias: None, | ||
| } | ||
|
|
@@ -478,6 +486,16 @@ pub struct BitcoindRestClientConfig { | |
| pub rest_port: u16, | ||
| } | ||
|
|
||
| /// Configuration for connecting to peers via the Tor Network. | ||
| #[derive(Debug, Clone)] | ||
| pub struct TorConfig { | ||
| /// Tor daemon SOCKS proxy address. | ||
| pub proxy_address: SocketAddress, | ||
|
|
||
| /// If set, all outbound peer connections will be made via the Tor SOCKS proxy. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I do wonder if we want to expose this right now, as it could be misleading given that all other connections (like Esplora/Eleectrum syncing, RGS updates, etc) would still go over clearnet? Maybe we should make this clear in the |
||
| pub proxy_all_outbound: bool, | ||
| } | ||
|
|
||
| /// Options which apply on a per-channel basis and may change at runtime or based on negotiation | ||
| /// with our counterparty. | ||
| #[derive(Copy, Clone, Debug, PartialEq, Eq)] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,9 @@ use std::time::Duration; | |
|
|
||
| use bitcoin::secp256k1::PublicKey; | ||
| use lightning::ln::msgs::SocketAddress; | ||
| use lightning::sign::RandomBytes; | ||
|
|
||
| use crate::config::TorConfig; | ||
| use crate::logger::{log_error, log_info, LdkLogger}; | ||
| use crate::types::PeerManager; | ||
| use crate::Error; | ||
|
|
@@ -25,16 +27,23 @@ where | |
| pending_connections: | ||
| Mutex<HashMap<PublicKey, Vec<tokio::sync::oneshot::Sender<Result<(), Error>>>>>, | ||
| peer_manager: Arc<PeerManager>, | ||
| tor_proxy_config: Option<TorConfig>, | ||
| tor_proxy_rng: Arc<RandomBytes>, | ||
| logger: L, | ||
| } | ||
|
|
||
| impl<L: Deref + Clone + Sync + Send> ConnectionManager<L> | ||
| where | ||
| L::Target: LdkLogger, | ||
| { | ||
| pub(crate) fn new(peer_manager: Arc<PeerManager>, logger: L) -> Self { | ||
| pub(crate) fn new( | ||
| peer_manager: Arc<PeerManager>, tor_proxy_config: Option<TorConfig>, | ||
| ephemeral_random_data: [u8; 32], logger: L, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's just have this take a |
||
| ) -> Self { | ||
| let pending_connections = Mutex::new(HashMap::new()); | ||
| Self { pending_connections, peer_manager, logger } | ||
| let tor_proxy_rng = Arc::new(RandomBytes::new(ephemeral_random_data)); | ||
|
|
||
| Self { pending_connections, peer_manager, tor_proxy_config, tor_proxy_rng, logger } | ||
| } | ||
|
|
||
| pub(crate) async fn connect_peer_if_necessary( | ||
|
|
@@ -64,27 +73,157 @@ where | |
|
|
||
| log_info!(self.logger, "Connecting to peer: {}@{}", node_id, addr); | ||
|
|
||
| let socket_addr = addr | ||
| .to_socket_addrs() | ||
| .map_err(|e| { | ||
| log_error!(self.logger, "Failed to resolve network address {}: {}", addr, e); | ||
| self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress)); | ||
| Error::InvalidSocketAddress | ||
| })? | ||
| .next() | ||
| .ok_or_else(|| { | ||
| log_error!(self.logger, "Failed to resolve network address {}", addr); | ||
| let res = match addr { | ||
| SocketAddress::OnionV2(old_onion_addr) => { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve network address {:?}: Resolution of OnionV2 addresses is currently unsupported.", | ||
| old_onion_addr | ||
| ); | ||
| self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress)); | ||
| Error::InvalidSocketAddress | ||
| })?; | ||
| return Err(Error::InvalidSocketAddress); | ||
| }, | ||
| SocketAddress::OnionV3 { .. } => { | ||
| let proxy_config = self.tor_proxy_config.as_ref().ok_or_else(|| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve network address {:?}: Tor usage is not configured.", | ||
| addr | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })?; | ||
| let proxy_addr = proxy_config | ||
| .proxy_address | ||
| .to_socket_addrs() | ||
| .map_err(|e| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve Tor proxy network address {}: {}", | ||
| proxy_config.proxy_address, | ||
| e | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })? | ||
| .next() | ||
| .ok_or_else(|| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve Tor proxy network address {}", | ||
| proxy_config.proxy_address | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })?; | ||
| let connection_future = lightning_net_tokio::tor_connect_outbound( | ||
| Arc::clone(&self.peer_manager), | ||
| node_id, | ||
| addr.clone(), | ||
| proxy_addr, | ||
| Arc::clone(&self.tor_proxy_rng), | ||
| ); | ||
| self.await_connection(connection_future, node_id, addr).await | ||
| }, | ||
| _ => { | ||
| let socket_addr = addr | ||
| .to_socket_addrs() | ||
| .map_err(|e| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve network address {}: {}", | ||
| addr, | ||
| e | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })? | ||
| .next() | ||
| .ok_or_else(|| { | ||
| log_error!(self.logger, "Failed to resolve network address {}", addr); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })?; | ||
| match &self.tor_proxy_config { | ||
| None | Some(TorConfig { proxy_all_outbound: false, .. }) => { | ||
| let connection_future = lightning_net_tokio::connect_outbound( | ||
| Arc::clone(&self.peer_manager), | ||
| node_id, | ||
| socket_addr, | ||
| ); | ||
| self.await_connection(connection_future, node_id, addr).await | ||
| }, | ||
| Some(proxy_config) => { | ||
| let proxy_addr = proxy_config | ||
| .proxy_address | ||
| .to_socket_addrs() | ||
| .map_err(|e| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve Tor proxy network address {}: {}", | ||
| proxy_config.proxy_address, | ||
| e | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })? | ||
| .next() | ||
| .ok_or_else(|| { | ||
| log_error!( | ||
| self.logger, | ||
| "Failed to resolve Tor proxy network address {}", | ||
| proxy_config.proxy_address | ||
| ); | ||
| self.propagate_result_to_subscribers( | ||
| &node_id, | ||
| Err(Error::InvalidSocketAddress), | ||
| ); | ||
| Error::InvalidSocketAddress | ||
| })?; | ||
| let connection_future = lightning_net_tokio::tor_connect_outbound( | ||
| Arc::clone(&self.peer_manager), | ||
| node_id, | ||
| addr.clone(), | ||
| proxy_addr, | ||
| Arc::clone(&self.tor_proxy_rng), | ||
| ); | ||
| self.await_connection(connection_future, node_id, addr).await | ||
| }, | ||
| } | ||
| }, | ||
| }; | ||
|
|
||
| self.propagate_result_to_subscribers(&node_id, res); | ||
|
|
||
| let connection_future = lightning_net_tokio::connect_outbound( | ||
| Arc::clone(&self.peer_manager), | ||
| node_id, | ||
| socket_addr, | ||
| ); | ||
| res | ||
| } | ||
|
|
||
| let res = match connection_future.await { | ||
| async fn await_connection<F, CF>( | ||
| &self, connection_future: F, node_id: PublicKey, addr: SocketAddress, | ||
| ) -> Result<(), Error> | ||
| where | ||
| F: std::future::Future<Output = Option<CF>>, | ||
| CF: std::future::Future<Output = ()>, | ||
| { | ||
| match connection_future.await { | ||
| Some(connection_closed_future) => { | ||
| let mut connection_closed_future = Box::pin(connection_closed_future); | ||
| loop { | ||
|
|
@@ -106,11 +245,7 @@ where | |
| log_error!(self.logger, "Failed to connect to peer: {}@{}", node_id, addr); | ||
| Err(Error::ConnectionFailed) | ||
| }, | ||
| }; | ||
|
|
||
| self.propagate_result_to_subscribers(&node_id, res); | ||
|
|
||
| res | ||
| } | ||
| } | ||
|
|
||
| fn register_or_subscribe_pending_connection( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -122,6 +122,8 @@ pub use builder::BuildError; | |
| #[cfg(not(feature = "uniffi"))] | ||
| pub use builder::NodeBuilder as Builder; | ||
| use chain::ChainSource; | ||
| #[cfg(feature = "uniffi")] | ||
| use config::TorConfig; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please just move this to the exports in the beginning of |
||
| use config::{ | ||
| default_user_config, may_announce_channel, AsyncPaymentsRole, ChannelConfig, Config, | ||
| NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.