Skip to content

Commit 463b1fc

Browse files
authored
Merge pull request #854 from tnull/2026-03-switch-to-async-lookup
Switch to async DNS resolution
2 parents 140451e + 105f835 commit 463b1fc

File tree

3 files changed

+126
-94
lines changed

3 files changed

+126
-94
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ bip21 = { version = "0.5", features = ["std"], default-features = false }
6666
base64 = { version = "0.22.1", default-features = false, features = ["std"] }
6767
getrandom = { version = "0.3", default-features = false }
6868
chrono = { version = "0.4", default-features = false, features = ["clock"] }
69-
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros" ] }
69+
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros", "net" ] }
7070
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"] }
7171
electrum-client = { version = "0.24.0", default-features = false, features = ["proxy", "use-rustls-ring"] }
7272
libc = "0.2"

src/connection.rs

Lines changed: 107 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// accordance with one or both of these licenses.
77

88
use std::collections::hash_map::{self, HashMap};
9-
use std::net::ToSocketAddrs;
109
use std::ops::Deref;
1110
use std::sync::{Arc, Mutex};
1211
use std::time::Duration;
@@ -15,7 +14,7 @@ use bitcoin::secp256k1::PublicKey;
1514
use lightning::ln::msgs::SocketAddress;
1615

1716
use crate::config::TorConfig;
18-
use crate::logger::{log_error, log_info, LdkLogger};
17+
use crate::logger::{log_debug, log_error, log_info, LdkLogger};
1918
use crate::types::{KeysManager, PeerManager};
2019
use crate::Error;
2120

@@ -56,6 +55,14 @@ where
5655

5756
pub(crate) async fn do_connect_peer(
5857
&self, node_id: PublicKey, addr: SocketAddress,
58+
) -> Result<(), Error> {
59+
let res = self.do_connect_peer_internal(node_id, addr).await;
60+
self.propagate_result_to_subscribers(&node_id, res);
61+
res
62+
}
63+
64+
async fn do_connect_peer_internal(
65+
&self, node_id: PublicKey, addr: SocketAddress,
5966
) -> Result<(), Error> {
6067
// First, we check if there is already an outbound connection in flight, if so, we just
6168
// await on the corresponding watch channel. The task driving the connection future will
@@ -71,15 +78,14 @@ where
7178

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

74-
let res = match addr {
81+
match addr {
7582
SocketAddress::OnionV2(old_onion_addr) => {
7683
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);
84+
self.logger,
85+
"Failed to resolve network address {:?}: Resolution of OnionV2 addresses is currently unsupported.",
86+
old_onion_addr
87+
);
88+
Err(Error::InvalidSocketAddress)
8389
},
8490
SocketAddress::OnionV3 { .. } => {
8591
let proxy_config = self.tor_proxy_config.as_ref().ok_or_else(|| {
@@ -88,87 +94,113 @@ where
8894
"Failed to resolve network address {:?}: Tor usage is not configured.",
8995
addr
9096
);
91-
self.propagate_result_to_subscribers(
92-
&node_id,
93-
Err(Error::InvalidSocketAddress),
94-
);
9597
Error::InvalidSocketAddress
9698
})?;
97-
let proxy_addr = proxy_config
98-
.proxy_address
99-
.to_socket_addrs()
100-
.map_err(|e| {
101-
log_error!(
102-
self.logger,
103-
"Failed to resolve Tor proxy network address {}: {}",
104-
proxy_config.proxy_address,
105-
e
106-
);
107-
self.propagate_result_to_subscribers(
108-
&node_id,
109-
Err(Error::InvalidSocketAddress),
110-
);
111-
Error::InvalidSocketAddress
112-
})?
113-
.next()
114-
.ok_or_else(|| {
115-
log_error!(
116-
self.logger,
117-
"Failed to resolve Tor proxy network address {}",
118-
proxy_config.proxy_address
119-
);
120-
self.propagate_result_to_subscribers(
121-
&node_id,
122-
Err(Error::InvalidSocketAddress),
123-
);
124-
Error::InvalidSocketAddress
125-
})?;
126-
let connection_future = lightning_net_tokio::tor_connect_outbound(
127-
Arc::clone(&self.peer_manager),
128-
node_id,
129-
addr.clone(),
130-
proxy_addr,
131-
Arc::clone(&self.keys_manager),
132-
);
133-
self.await_connection(connection_future, node_id, addr).await
99+
let resolved_addrs: Vec<_> =
100+
tokio::net::lookup_host(proxy_config.proxy_address.to_string())
101+
.await
102+
.map_err(|e| {
103+
log_error!(
104+
self.logger,
105+
"Failed to resolve Tor proxy network address {}: {}",
106+
proxy_config.proxy_address,
107+
e
108+
);
109+
Error::InvalidSocketAddress
110+
})?
111+
.collect();
112+
113+
if resolved_addrs.is_empty() {
114+
log_error!(
115+
self.logger,
116+
"Failed to resolve Tor proxy network address {}",
117+
proxy_config.proxy_address
118+
);
119+
return Err(Error::InvalidSocketAddress);
120+
}
121+
122+
let mut res = Err(Error::ConnectionFailed);
123+
let mut had_failures = false;
124+
for proxy_addr in resolved_addrs {
125+
let connection_future = lightning_net_tokio::tor_connect_outbound(
126+
Arc::clone(&self.peer_manager),
127+
node_id,
128+
addr.clone(),
129+
proxy_addr,
130+
Arc::clone(&self.keys_manager),
131+
);
132+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
133+
if res.is_ok() {
134+
if had_failures {
135+
log_info!(
136+
self.logger,
137+
"Successfully connected to peer {}@{} via resolved proxy address {} after previous attempts failed.",
138+
node_id, addr, proxy_addr
139+
);
140+
}
141+
break;
142+
}
143+
had_failures = true;
144+
log_debug!(
145+
self.logger,
146+
"Failed to connect to peer {}@{} via resolved proxy address {}.",
147+
node_id,
148+
addr,
149+
proxy_addr
150+
);
151+
}
152+
res
134153
},
135154
_ => {
136-
let socket_addr = addr
137-
.to_socket_addrs()
155+
let resolved_addrs: Vec<_> = tokio::net::lookup_host(addr.to_string())
156+
.await
138157
.map_err(|e| {
139158
log_error!(
140159
self.logger,
141160
"Failed to resolve network address {}: {}",
142161
addr,
143162
e
144163
);
145-
self.propagate_result_to_subscribers(
146-
&node_id,
147-
Err(Error::InvalidSocketAddress),
148-
);
149164
Error::InvalidSocketAddress
150165
})?
151-
.next()
152-
.ok_or_else(|| {
153-
log_error!(self.logger, "Failed to resolve network address {}", addr);
154-
self.propagate_result_to_subscribers(
155-
&node_id,
156-
Err(Error::InvalidSocketAddress),
157-
);
158-
Error::InvalidSocketAddress
159-
})?;
160-
let connection_future = lightning_net_tokio::connect_outbound(
161-
Arc::clone(&self.peer_manager),
162-
node_id,
163-
socket_addr,
164-
);
165-
self.await_connection(connection_future, node_id, addr).await
166-
},
167-
};
166+
.collect();
168167

169-
self.propagate_result_to_subscribers(&node_id, res);
168+
if resolved_addrs.is_empty() {
169+
log_error!(self.logger, "Failed to resolve network address {}", addr);
170+
return Err(Error::InvalidSocketAddress);
171+
}
170172

171-
res
173+
let mut res = Err(Error::ConnectionFailed);
174+
let mut had_failures = false;
175+
for socket_addr in resolved_addrs {
176+
let connection_future = lightning_net_tokio::connect_outbound(
177+
Arc::clone(&self.peer_manager),
178+
node_id,
179+
socket_addr,
180+
);
181+
res = self.await_connection(connection_future, node_id, addr.clone()).await;
182+
if res.is_ok() {
183+
if had_failures {
184+
log_info!(
185+
self.logger,
186+
"Successfully connected to peer {}@{} via resolved address {} after previous attempts failed.",
187+
node_id, addr, socket_addr
188+
);
189+
}
190+
break;
191+
}
192+
had_failures = true;
193+
log_debug!(
194+
self.logger,
195+
"Failed to connect to peer {}@{} via resolved address {}.",
196+
node_id,
197+
addr,
198+
socket_addr
199+
);
200+
}
201+
res
202+
},
203+
}
172204
}
173205

174206
async fn await_connection<F, CF>(

src/lib.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ mod types;
108108
mod wallet;
109109

110110
use std::default::Default;
111-
use std::net::ToSocketAddrs;
112111
use std::sync::{Arc, Mutex, RwLock};
113112
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
114113
#[cfg(cycle_tests)]
@@ -361,28 +360,29 @@ impl Node {
361360
let peer_manager_connection_handler = Arc::clone(&self.peer_manager);
362361
let listening_logger = Arc::clone(&self.logger);
363362

364-
let mut bind_addrs = Vec::with_capacity(listening_addresses.len());
365-
366-
for listening_addr in listening_addresses {
367-
let resolved_address = listening_addr.to_socket_addrs().map_err(|e| {
368-
log_error!(
369-
self.logger,
370-
"Unable to resolve listening address: {:?}. Error details: {}",
371-
listening_addr,
372-
e,
373-
);
374-
Error::InvalidSocketAddress
375-
})?;
376-
377-
bind_addrs.extend(resolved_address);
378-
}
379-
380363
let logger = Arc::clone(&listening_logger);
364+
let listening_addrs = listening_addresses.clone();
381365
let listeners = self.runtime.block_on(async move {
366+
let mut bind_addrs = Vec::with_capacity(listening_addrs.len());
367+
368+
for listening_addr in &listening_addrs {
369+
let resolved =
370+
tokio::net::lookup_host(listening_addr.to_string()).await.map_err(|e| {
371+
log_error!(
372+
logger,
373+
"Unable to resolve listening address: {:?}. Error details: {}",
374+
listening_addr,
375+
e,
376+
);
377+
Error::InvalidSocketAddress
378+
})?;
379+
bind_addrs.extend(resolved);
380+
}
381+
382382
let mut listeners = Vec::new();
383383

384384
// Try to bind to all addresses
385-
for addr in &*bind_addrs {
385+
for addr in &bind_addrs {
386386
match tokio::net::TcpListener::bind(addr).await {
387387
Ok(listener) => {
388388
log_trace!(logger, "Listener bound to {}", addr);

0 commit comments

Comments
 (0)