⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,16 @@ impl NodeBuilder {
Ok(self)
}

/// Set the address which [`Node`] will use as a Tor proxy to connect to peer OnionV3 addresses.
///
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
///
/// [`tor_proxy_address`]: Config::tor_proxy_address
pub fn set_tor_proxy_address(&mut self, tor_proxy_address: core::net::SocketAddr) -> &mut Self {
self.config.tor_proxy_address = Some(tor_proxy_address);
self
}

/// Sets the node alias that will be used when broadcasting announcements to the gossip
/// network.
///
Expand Down Expand Up @@ -904,6 +914,15 @@ impl ArcedNodeBuilder {
self.inner.write().unwrap().set_announcement_addresses(announcement_addresses).map(|_| ())
}

/// Set the address which [`Node`] will use as a Tor proxy to connect to peer OnionV3 addresses.
///
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
///
/// [`tor_proxy_address`]: Config::tor_proxy_address
pub fn set_tor_proxy_address(&mut self, tor_proxy_address: core::net::SocketAddr) {
self.config.tor_proxy_address = Some(tor_proxy_address);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than replicating the functionality, please just call through to inner as we do elsewhere in this builder. This avoids their behavior getting out-of-sync over time.

}

/// Sets the node alias that will be used when broadcasting announcements to the gossip
/// network.
///
Expand Down Expand Up @@ -1683,8 +1702,12 @@ fn build_with_store_internal(

liquidity_source.as_ref().map(|l| l.set_peer_manager(Arc::downgrade(&peer_manager)));

let connection_manager =
Arc::new(ConnectionManager::new(Arc::clone(&peer_manager), Arc::clone(&logger)));
let connection_manager = Arc::new(ConnectionManager::new(
Arc::clone(&peer_manager),
config.tor_proxy_address.clone(),
ephemeral_bytes,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be used to derive passwords sent in plaintext to the SOCKS5 proxy, so out of caution I would have passed a seed here that is different from the seed passed to the PeerManager to derive BOLT 8 per-connection ephemeral keys.

The KeysManager entropy source is also a chacha20 so seems to me we can cheaply do another keys_manager.get_secure_random_bytes();

Arc::clone(&logger),
));

let output_sweeper = match sweeper_bytes_res {
Ok(output_sweeper) => Arc::new(output_sweeper),
Expand Down
7 changes: 7 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ pub struct Config {
///
/// [`listening_addresses`]: Config::listening_addresses
pub announcement_addresses: Option<Vec<SocketAddress>>,
/// The address which the node will use as a Tor proxy to connect to peer OnionV3 addresses.
///
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
///
/// [`tor_proxy_address`]: Config::tor_proxy_address
pub tor_proxy_address: Option<core::net::SocketAddr>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think it would be preferable to drop this field and just add a separate Option<TorConfig> or similar. The struct TorConfig would then also allow to add tor-specific settings, such as the ones mentioned below.

Also note that we'll want to expose all of the new APIs to bindings, so you'll need to make the corresponding changes in bindings/ldk_node.udl and use SocketAddress, not SocketAddr.

/// The node alias that will be used when broadcasting announcements to the gossip network.
///
/// The provided alias must be a valid UTF-8 string and no longer than 32 bytes in total.
Expand Down Expand Up @@ -201,6 +207,7 @@ impl Default for Config {
network: DEFAULT_NETWORK,
listening_addresses: None,
announcement_addresses: None,
tor_proxy_address: None,
trusted_peers_0conf: Vec::new(),
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
anchor_channels_config: Some(AnchorChannelsConfig::default()),
Expand Down
96 changes: 73 additions & 23 deletions src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::time::Duration;

use bitcoin::secp256k1::PublicKey;
use lightning::ln::msgs::SocketAddress;
use lightning::sign::RandomBytes;

use crate::logger::{log_error, log_info, LdkLogger};
use crate::types::PeerManager;
Expand All @@ -25,16 +26,23 @@ where
pending_connections:
Mutex<HashMap<PublicKey, Vec<tokio::sync::oneshot::Sender<Result<(), Error>>>>>,
peer_manager: Arc<PeerManager>,
tor_proxy_addr: Option<core::net::SocketAddr>,
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_addr: Option<core::net::SocketAddr>,
ephemeral_random_data: [u8; 32], logger: L,
) -> 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_addr, tor_proxy_rng, logger }
}

pub(crate) async fn connect_peer_if_necessary(
Expand Down Expand Up @@ -64,27 +72,73 @@ 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 = if let SocketAddress::OnionV2(old_onion_addr) = addr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: did you consider using a match statement here?

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));
return Err(Error::InvalidSocketAddress);
} else if let SocketAddress::OnionV3 { .. } = addr {
let proxy_addr = self.tor_proxy_addr.ok_or_else(|| {
log_error!(
self.logger,
"Failed to resolve network address {:?}: Tor proxy address is unset.",
addr
);
self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress));
Error::InvalidSocketAddress
})?;
let connection_future = lightning_net_tokio::tor_connect_outbound(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to allow people to proxy the other types over tor as well ? Have to be careful with adding more settings, but I'm thinking of an analog to the always-use-proxy=true CLN setting.

Could be done in a follow-up if preferred.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, that would be a useful setting...

I'm open to add that on to this PR, would need another cfg setting I suppose.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, that would be a useful setting...

I'm open to add that on to this PR, would need another cfg setting I suppose.

Let's just add this as a flag in above mentioned TorConfig struct?

Arc::clone(&self.peer_manager),
node_id,
addr.clone(),
proxy_addr,
self.tor_proxy_rng.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Would have used Arc::clone(&self.tor_proxy_rng) here, same style as the peer manager above, just to make it very clear we are only creating a new pointer to the same state, and not cloning the state itself.

);
self.await_connection(connection_future, node_id, addr).await
} else {
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
})?;
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
};

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 {
Expand All @@ -106,11 +160,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(
Expand Down
Loading