Skip to content

Commit 96855e9

Browse files
committed
Add Tor support for outbound connections
1 parent 12ce2d1 commit 96855e9

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

ldk-server/ldk-server-config.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,8 @@ client_trusts_lsp = false
8888
## A token we may require to be sent by the clients.
8989
## If set, only requests matching this token will be accepted. (uncomment and set if required)
9090
# require_token = ""
91+
92+
# Tor Config
93+
[tor]
94+
# Only connections to OnionV3 peers will be made via this proxy; other connections (IPv4 peers, Electrum server) will not be routed over Tor.
95+
#proxy_address = "" # Tor daemon SOCKS proxy address.

ldk-server/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ fn main() {
180180
);
181181
}
182182

183+
if let Some(tor_config) = config_file.tor_config {
184+
let tor_config = ldk_node::config::TorConfig { proxy_address: tor_config.proxy_address };
185+
let _ = builder.set_tor_config(tor_config);
186+
}
187+
183188
// LSPS2 support is highly experimental and for testing purposes only.
184189
#[cfg(feature = "experimental-lsps2-support")]
185190
builder.set_liquidity_provider_lsps2(

ldk-server/src/util/config.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub struct Config {
6060
pub log_level: LevelFilter,
6161
pub log_file_path: Option<String>,
6262
pub pathfinding_scores_source_url: Option<String>,
63+
pub tor_config: Option<TorConfig>,
6364
}
6465

6566
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -83,6 +84,11 @@ pub enum ChainSource {
8384
Esplora { server_url: String },
8485
}
8586

87+
#[derive(Debug, PartialEq, Eq)]
88+
pub struct TorConfig {
89+
pub proxy_address: SocketAddress,
90+
}
91+
8692
/// A builder for `Config`.
8793
#[derive(Default)]
8894
struct ConfigBuilder {
@@ -105,6 +111,7 @@ struct ConfigBuilder {
105111
log_level: Option<String>,
106112
log_file_path: Option<String>,
107113
pathfinding_scores_source_url: Option<String>,
114+
tor_proxy_address: Option<String>,
108115
}
109116

110117
impl ConfigBuilder {
@@ -164,6 +171,10 @@ impl ConfigBuilder {
164171
hosts: tls.hosts.unwrap_or_default(),
165172
});
166173
}
174+
175+
if let Some(tor) = toml.tor {
176+
self.tor_proxy_address = Some(tor.proxy_address)
177+
}
167178
}
168179

169180
fn merge_args(&mut self, args: &ArgsConfig) {
@@ -206,6 +217,10 @@ impl ConfigBuilder {
206217
if let Some(pathfinding_scores_source_url) = &args.pathfinding_scores_source_url {
207218
self.pathfinding_scores_source_url = Some(pathfinding_scores_source_url.clone());
208219
}
220+
221+
if let Some(tor_proxy_address) = &args.tor_proxy_address {
222+
self.tor_proxy_address = Some(tor_proxy_address.clone());
223+
}
209224
}
210225

211226
fn build(self) -> io::Result<Config> {
@@ -364,6 +379,18 @@ impl ConfigBuilder {
364379

365380
let pathfinding_scores_source_url = self.pathfinding_scores_source_url;
366381

382+
let tor_proxy_address: Option<SocketAddress> = self
383+
.tor_proxy_address
384+
.map(|addrs| {
385+
SocketAddress::from_str(&addrs).map_err(|e| {
386+
io::Error::new(
387+
io::ErrorKind::InvalidInput,
388+
format!("Invalid proxy address configured: {}", e),
389+
)
390+
})
391+
})
392+
.transpose()?;
393+
367394
Ok(Config {
368395
network,
369396
listening_addrs,
@@ -381,6 +408,7 @@ impl ConfigBuilder {
381408
log_level,
382409
log_file_path: self.log_file_path,
383410
pathfinding_scores_source_url,
411+
tor_config: tor_proxy_address.map(|proxy_address| TorConfig { proxy_address }),
384412
})
385413
}
386414
}
@@ -397,6 +425,7 @@ pub struct TomlConfig {
397425
liquidity: Option<LiquidityConfig>,
398426
log: Option<LogConfig>,
399427
tls: Option<TomlTlsConfig>,
428+
tor: Option<TomlTorConfig>,
400429
}
401430

402431
#[derive(Deserialize, Serialize)]
@@ -456,6 +485,11 @@ struct TomlTlsConfig {
456485
hosts: Option<Vec<String>>,
457486
}
458487

488+
#[derive(Deserialize, Serialize)]
489+
struct TomlTorConfig {
490+
proxy_address: String,
491+
}
492+
459493
#[derive(Deserialize, Serialize)]
460494
struct LiquidityConfig {
461495
lsps2_client: Option<LSPSClientTomlConfig>,
@@ -614,6 +648,13 @@ pub struct ArgsConfig {
614648
help = "The external scores source that is merged into the local scoring system to improve routing."
615649
)]
616650
pathfinding_scores_source_url: Option<String>,
651+
652+
#[arg(
653+
long,
654+
env = "LDK_SERVER_TOR_PROXY_ADDRESS",
655+
help = "Tor daemon SOCKS proxy address. Only connections to OnionV3 peers will be made via this proxy; other connections (IPv4 peers, Electrum server) will not be routed over Tor."
656+
)]
657+
tor_proxy_address: Option<String>,
617658
}
618659

619660
pub fn load_config(args: &ArgsConfig) -> io::Result<Config> {
@@ -732,6 +773,9 @@ mod tests {
732773
min_payment_size_msat = 10000000 # 10,000 satoshis
733774
max_payment_size_msat = 25000000000 # 0.25 BTC
734775
client_trusts_lsp = true
776+
777+
[tor]
778+
proxy_address = "vww6ybal4bd7szmgncyruucpgfkqahzddi37ktce36gpflljhvevubid.onion:9735"
735779
"#;
736780

737781
fn default_args_config() -> ArgsConfig {
@@ -747,6 +791,7 @@ mod tests {
747791
storage_dir_path: Some(String::from("/tmp_cli")),
748792
node_alias: Some(String::from("LDK Server CLI")),
749793
pathfinding_scores_source_url: Some(String::from("https://example.com/")),
794+
tor_proxy_address: None,
750795
}
751796
}
752797

@@ -763,6 +808,7 @@ mod tests {
763808
bitcoind_rpc_password: None,
764809
storage_dir_path: None,
765810
pathfinding_scores_source_url: None,
811+
tor_proxy_address: None,
766812
}
767813
}
768814

@@ -839,6 +885,12 @@ mod tests {
839885
log_level: LevelFilter::Trace,
840886
log_file_path: Some("/var/log/ldk-server.log".to_string()),
841887
pathfinding_scores_source_url: None,
888+
tor_config: Some(TorConfig {
889+
proxy_address: SocketAddress::from_str(
890+
"vww6ybal4bd7szmgncyruucpgfkqahzddi37ktce36gpflljhvevubid.onion:9735",
891+
)
892+
.unwrap(),
893+
}),
842894
};
843895

844896
assert_eq!(config.listening_addrs, expected.listening_addrs);
@@ -857,6 +909,7 @@ mod tests {
857909
assert_eq!(config.log_level, expected.log_level);
858910
assert_eq!(config.log_file_path, expected.log_file_path);
859911
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
912+
assert_eq!(config.tor_config, expected.tor_config);
860913

861914
// Test case where only electrum is set
862915

@@ -1162,6 +1215,7 @@ mod tests {
11621215
log_level: LevelFilter::Trace,
11631216
log_file_path: Some("/var/log/ldk-server.log".to_string()),
11641217
pathfinding_scores_source_url: Some("https://example.com/".to_string()),
1218+
tor_config: None,
11651219
};
11661220

11671221
assert_eq!(config.listening_addrs, expected.listening_addrs);
@@ -1175,6 +1229,7 @@ mod tests {
11751229
assert_eq!(config.rabbitmq_exchange_name, expected.rabbitmq_exchange_name);
11761230
assert!(config.lsps2_service_config.is_none());
11771231
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
1232+
assert_eq!(config.tor_config, expected.tor_config);
11781233
}
11791234

11801235
#[test]
@@ -1273,6 +1328,12 @@ mod tests {
12731328
log_level: LevelFilter::Trace,
12741329
log_file_path: Some("/var/log/ldk-server.log".to_string()),
12751330
pathfinding_scores_source_url: Some("https://example.com/".to_string()),
1331+
tor_config: Some(TorConfig {
1332+
proxy_address: SocketAddress::from_str(
1333+
"vww6ybal4bd7szmgncyruucpgfkqahzddi37ktce36gpflljhvevubid.onion:9735",
1334+
)
1335+
.unwrap(),
1336+
}),
12761337
};
12771338

12781339
assert_eq!(config.listening_addrs, expected.listening_addrs);
@@ -1288,6 +1349,7 @@ mod tests {
12881349
#[cfg(feature = "experimental-lsps2-support")]
12891350
assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some());
12901351
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
1352+
assert_eq!(config.tor_config, expected.tor_config);
12911353
}
12921354

12931355
#[test]

0 commit comments

Comments
 (0)