Skip to content

Commit 1ce0c38

Browse files
committed
Add Tor support for outbound connections via SOCKS
1 parent d261724 commit 1ce0c38

File tree

3 files changed

+105
-25
lines changed

3 files changed

+105
-25
lines changed

src/builder.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,16 @@ impl NodeBuilder {
518518
Ok(self)
519519
}
520520

521+
/// Set the address which [`Node`] will use as a Tor proxy to connect to peer OnionV3 addresses.
522+
///
523+
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
524+
///
525+
/// [`tor_proxy_address`]: Config::tor_proxy_address
526+
pub fn set_tor_proxy_address(&mut self, tor_proxy_address: core::net::SocketAddr) -> &mut Self {
527+
self.config.tor_proxy_address = Some(tor_proxy_address);
528+
self
529+
}
530+
521531
/// Sets the node alias that will be used when broadcasting announcements to the gossip
522532
/// network.
523533
///
@@ -904,6 +914,15 @@ impl ArcedNodeBuilder {
904914
self.inner.write().unwrap().set_announcement_addresses(announcement_addresses).map(|_| ())
905915
}
906916

917+
/// Set the address which [`Node`] will use as a Tor proxy to connect to peer OnionV3 addresses.
918+
///
919+
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
920+
///
921+
/// [`tor_proxy_address`]: Config::tor_proxy_address
922+
pub fn set_tor_proxy_address(&mut self, tor_proxy_address: core::net::SocketAddr) {
923+
self.config.tor_proxy_address = Some(tor_proxy_address);
924+
}
925+
907926
/// Sets the node alias that will be used when broadcasting announcements to the gossip
908927
/// network.
909928
///
@@ -1683,8 +1702,12 @@ fn build_with_store_internal(
16831702

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

1686-
let connection_manager =
1687-
Arc::new(ConnectionManager::new(Arc::clone(&peer_manager), Arc::clone(&logger)));
1705+
let connection_manager = Arc::new(ConnectionManager::new(
1706+
Arc::clone(&peer_manager),
1707+
config.tor_proxy_address.clone(),
1708+
ephemeral_bytes,
1709+
Arc::clone(&logger),
1710+
));
16881711

16891712
let output_sweeper = match sweeper_bytes_res {
16901713
Ok(output_sweeper) => Arc::new(output_sweeper),

src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ pub struct Config {
149149
///
150150
/// [`listening_addresses`]: Config::listening_addresses
151151
pub announcement_addresses: Option<Vec<SocketAddress>>,
152+
/// The address which the node will use as a Tor proxy to connect to peer OnionV3 addresses.
153+
///
154+
/// **Note**: If unset, connecting to peer OnionV3 addresses will fail.
155+
///
156+
/// [`tor_proxy_address`]: Config::tor_proxy_address
157+
pub tor_proxy_address: Option<core::net::SocketAddr>,
152158
/// The node alias that will be used when broadcasting announcements to the gossip network.
153159
///
154160
/// The provided alias must be a valid UTF-8 string and no longer than 32 bytes in total.
@@ -201,6 +207,7 @@ impl Default for Config {
201207
network: DEFAULT_NETWORK,
202208
listening_addresses: None,
203209
announcement_addresses: None,
210+
tor_proxy_address: None,
204211
trusted_peers_0conf: Vec::new(),
205212
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
206213
anchor_channels_config: Some(AnchorChannelsConfig::default()),

src/connection.rs

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::time::Duration;
1313

1414
use bitcoin::secp256k1::PublicKey;
1515
use lightning::ln::msgs::SocketAddress;
16+
use lightning::sign::RandomBytes;
1617

1718
use crate::logger::{log_error, log_info, LdkLogger};
1819
use crate::types::PeerManager;
@@ -25,16 +26,23 @@ where
2526
pending_connections:
2627
Mutex<HashMap<PublicKey, Vec<tokio::sync::oneshot::Sender<Result<(), Error>>>>>,
2728
peer_manager: Arc<PeerManager>,
29+
tor_proxy_addr: Option<core::net::SocketAddr>,
30+
tor_proxy_rng: Arc<RandomBytes>,
2831
logger: L,
2932
}
3033

3134
impl<L: Deref + Clone + Sync + Send> ConnectionManager<L>
3235
where
3336
L::Target: LdkLogger,
3437
{
35-
pub(crate) fn new(peer_manager: Arc<PeerManager>, logger: L) -> Self {
38+
pub(crate) fn new(
39+
peer_manager: Arc<PeerManager>, tor_proxy_addr: Option<core::net::SocketAddr>,
40+
ephemeral_random_data: [u8; 32], logger: L,
41+
) -> Self {
3642
let pending_connections = Mutex::new(HashMap::new());
37-
Self { pending_connections, peer_manager, logger }
43+
let tor_proxy_rng = Arc::new(RandomBytes::new(ephemeral_random_data));
44+
45+
Self { pending_connections, peer_manager, tor_proxy_addr, tor_proxy_rng, logger }
3846
}
3947

4048
pub(crate) async fn connect_peer_if_necessary(
@@ -64,27 +72,73 @@ where
6472

6573
log_info!(self.logger, "Connecting to peer: {}@{}", node_id, addr);
6674

67-
let socket_addr = addr
68-
.to_socket_addrs()
69-
.map_err(|e| {
70-
log_error!(self.logger, "Failed to resolve network address {}: {}", addr, e);
71-
self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress));
72-
Error::InvalidSocketAddress
73-
})?
74-
.next()
75-
.ok_or_else(|| {
76-
log_error!(self.logger, "Failed to resolve network address {}", addr);
75+
let res = if let SocketAddress::OnionV2(old_onion_addr) = addr {
76+
log_error!(
77+
self.logger,
78+
"Failed to resolve network address {:?}: Resolution of OnionV2 addresses is currently unsupported.",
79+
old_onion_addr
80+
);
81+
self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress));
82+
return Err(Error::InvalidSocketAddress);
83+
} else if let SocketAddress::OnionV3 { .. } = addr {
84+
let proxy_addr = self.tor_proxy_addr.ok_or_else(|| {
85+
log_error!(
86+
self.logger,
87+
"Failed to resolve network address {:?}: Tor proxy address is unset.",
88+
addr
89+
);
7790
self.propagate_result_to_subscribers(&node_id, Err(Error::InvalidSocketAddress));
7891
Error::InvalidSocketAddress
7992
})?;
93+
let connection_future = lightning_net_tokio::tor_connect_outbound(
94+
Arc::clone(&self.peer_manager),
95+
node_id,
96+
addr.clone(),
97+
proxy_addr,
98+
self.tor_proxy_rng.clone(),
99+
);
100+
self.await_connection(connection_future, node_id, addr).await
101+
} else {
102+
let socket_addr = addr
103+
.to_socket_addrs()
104+
.map_err(|e| {
105+
log_error!(self.logger, "Failed to resolve network address {}: {}", addr, e);
106+
self.propagate_result_to_subscribers(
107+
&node_id,
108+
Err(Error::InvalidSocketAddress),
109+
);
110+
Error::InvalidSocketAddress
111+
})?
112+
.next()
113+
.ok_or_else(|| {
114+
log_error!(self.logger, "Failed to resolve network address {}", addr);
115+
self.propagate_result_to_subscribers(
116+
&node_id,
117+
Err(Error::InvalidSocketAddress),
118+
);
119+
Error::InvalidSocketAddress
120+
})?;
121+
let connection_future = lightning_net_tokio::connect_outbound(
122+
Arc::clone(&self.peer_manager),
123+
node_id,
124+
socket_addr,
125+
);
126+
self.await_connection(connection_future, node_id, addr).await
127+
};
128+
129+
self.propagate_result_to_subscribers(&node_id, res);
80130

81-
let connection_future = lightning_net_tokio::connect_outbound(
82-
Arc::clone(&self.peer_manager),
83-
node_id,
84-
socket_addr,
85-
);
131+
res
132+
}
86133

87-
let res = match connection_future.await {
134+
async fn await_connection<F, CF>(
135+
&self, connection_future: F, node_id: PublicKey, addr: SocketAddress,
136+
) -> Result<(), Error>
137+
where
138+
F: std::future::Future<Output = Option<CF>>,
139+
CF: std::future::Future<Output = ()>,
140+
{
141+
match connection_future.await {
88142
Some(connection_closed_future) => {
89143
let mut connection_closed_future = Box::pin(connection_closed_future);
90144
loop {
@@ -106,11 +160,7 @@ where
106160
log_error!(self.logger, "Failed to connect to peer: {}@{}", node_id, addr);
107161
Err(Error::ConnectionFailed)
108162
},
109-
};
110-
111-
self.propagate_result_to_subscribers(&node_id, res);
112-
113-
res
163+
}
114164
}
115165

116166
fn register_or_subscribe_pending_connection(

0 commit comments

Comments
 (0)