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
5 changes: 5 additions & 0 deletions ldk-server/ldk-server-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,8 @@ poll_metrics_interval = 60 # The polling interval for metrics in seconds.
# The auth details below are optional, but uncommenting the fields means enabling basic auth, so valid fields must be supplied.
#username = "" # The username required to access the metrics endpoint (Basic Auth).
#password = "" # The password required to access the metrics endpoint (Basic Auth).

# Tor Config
[tor]
# Only connections to OnionV3 peers will be made via this proxy; other connections (IPv4 peers, Electrum server) will not be routed over Tor.
#proxy_address = "" # Tor daemon SOCKS proxy address.
8 changes: 8 additions & 0 deletions ldk-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ fn main() {
);
}

if let Some(tor_config) = config_file.tor_config {
let tor_config = ldk_node::config::TorConfig { proxy_address: tor_config.proxy_address };
if let Err(e) = builder.set_tor_config(tor_config) {
error!("Failed to configure Tor proxy: {e}");
std::process::exit(-1);
}
}

// LSPS2 support is highly experimental and for testing purposes only.
#[cfg(feature = "experimental-lsps2-support")]
builder.set_liquidity_provider_lsps2(
Expand Down
56 changes: 56 additions & 0 deletions ldk-server/src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub struct Config {
pub poll_metrics_interval: Option<u64>,
pub metrics_username: Option<String>,
pub metrics_password: Option<String>,
pub tor_config: Option<TorConfig>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand All @@ -87,6 +88,11 @@ pub enum ChainSource {
Esplora { server_url: String },
}

#[derive(Debug, PartialEq, Eq)]
pub struct TorConfig {
pub proxy_address: SocketAddress,
}

/// A builder for `Config`.
#[derive(Default)]
struct ConfigBuilder {
Expand All @@ -113,6 +119,7 @@ struct ConfigBuilder {
poll_metrics_interval: Option<u64>,
metrics_username: Option<String>,
metrics_password: Option<String>,
tor_proxy_address: Option<String>,
}

impl ConfigBuilder {
Expand Down Expand Up @@ -180,6 +187,10 @@ impl ConfigBuilder {
self.metrics_username = metrics.username.or(self.metrics_username.clone());
self.metrics_password = metrics.password.or(self.metrics_password.clone());
}

if let Some(tor) = toml.tor {
self.tor_proxy_address = Some(tor.proxy_address)
}
}

fn merge_args(&mut self, args: &ArgsConfig) {
Expand Down Expand Up @@ -238,6 +249,10 @@ impl ConfigBuilder {
if let Some(metrics_password) = &args.metrics_password {
self.metrics_password = Some(metrics_password.clone());
}

if let Some(tor_proxy_address) = &args.tor_proxy_address {
self.tor_proxy_address = Some(tor_proxy_address.clone());
}
}

fn build(self) -> io::Result<Config> {
Expand Down Expand Up @@ -410,6 +425,18 @@ impl ConfigBuilder {
"Both `metrics.username` and `metrics.password` must be set if authentication is used for metrics."));
}

let tor_proxy_address: Option<SocketAddress> = self
.tor_proxy_address
.map(|addrs| {
SocketAddress::from_str(&addrs).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("Invalid proxy address configured: {}", e),
)
})
})
.transpose()?;

Ok(Config {
network,
listening_addrs,
Expand All @@ -431,6 +458,7 @@ impl ConfigBuilder {
poll_metrics_interval,
metrics_username,
metrics_password,
tor_config: tor_proxy_address.map(|proxy_address| TorConfig { proxy_address }),
})
}
}
Expand All @@ -448,6 +476,7 @@ pub struct TomlConfig {
log: Option<LogConfig>,
tls: Option<TomlTlsConfig>,
metrics: Option<MetricsTomlConfig>,
tor: Option<TomlTorConfig>,
}

#[derive(Deserialize, Serialize)]
Expand Down Expand Up @@ -515,6 +544,11 @@ struct MetricsTomlConfig {
password: Option<String>,
}

#[derive(Deserialize, Serialize)]
struct TomlTorConfig {
proxy_address: String,
}

#[derive(Deserialize, Serialize)]
struct LiquidityConfig {
lsps2_client: Option<LSPSClientTomlConfig>,
Expand Down Expand Up @@ -702,6 +736,13 @@ pub struct ArgsConfig {
help = "The password required to access the metrics endpoint (Basic Auth)."
)]
metrics_password: Option<String>,

#[arg(
long,
env = "LDK_SERVER_TOR_PROXY_ADDRESS",
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."
)]
tor_proxy_address: Option<String>,
}

pub fn load_config(args: &ArgsConfig) -> io::Result<Config> {
Expand Down Expand Up @@ -820,6 +861,9 @@ mod tests {
min_payment_size_msat = 10000000 # 10,000 satoshis
max_payment_size_msat = 25000000000 # 0.25 BTC
client_trusts_lsp = true

[tor]
proxy_address = "127.0.0.1:9050"
"#;

fn default_args_config() -> ArgsConfig {
Expand All @@ -839,6 +883,7 @@ mod tests {
poll_metrics_interval: None,
metrics_username: None,
metrics_password: None,
tor_proxy_address: None,
}
}

Expand All @@ -859,6 +904,7 @@ mod tests {
poll_metrics_interval: None,
metrics_username: None,
metrics_password: None,
tor_proxy_address: None,
}
}

Expand Down Expand Up @@ -939,6 +985,9 @@ mod tests {
poll_metrics_interval: None,
metrics_username: None,
metrics_password: None,
tor_config: Some(TorConfig {
proxy_address: SocketAddress::from_str("127.0.0.1:9050").unwrap(),
}),
};

assert_eq!(config.listening_addrs, expected.listening_addrs);
Expand All @@ -958,6 +1007,7 @@ mod tests {
assert_eq!(config.log_file_path, expected.log_file_path);
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
assert_eq!(config.tor_config, expected.tor_config);

// Test case where only electrum is set

Expand Down Expand Up @@ -1267,6 +1317,7 @@ mod tests {
poll_metrics_interval: None,
metrics_username: None,
metrics_password: None,
tor_config: None,
};

assert_eq!(config.listening_addrs, expected.listening_addrs);
Expand All @@ -1281,6 +1332,7 @@ mod tests {
assert!(config.lsps2_service_config.is_none());
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
assert_eq!(config.tor_config, expected.tor_config);
}

#[test]
Expand Down Expand Up @@ -1383,6 +1435,9 @@ mod tests {
poll_metrics_interval: None,
metrics_username: None,
metrics_password: None,
tor_config: Some(TorConfig {
proxy_address: SocketAddress::from_str("127.0.0.1:9050").unwrap(),
}),
};

assert_eq!(config.listening_addrs, expected.listening_addrs);
Expand All @@ -1399,6 +1454,7 @@ mod tests {
assert_eq!(config.lsps2_service_config.is_some(), expected.lsps2_service_config.is_some());
assert_eq!(config.pathfinding_scores_source_url, expected.pathfinding_scores_source_url);
assert_eq!(config.metrics_enabled, expected.metrics_enabled);
assert_eq!(config.tor_config, expected.tor_config);
}

#[test]
Expand Down