fix: systemd resource limits, Tor rotation transition, unwrap elimination, RPC timeouts
- I2: Add MemoryMax=4G, LimitNOFILE=65535, TasksMax=2048 to systemd service - I3: Tor rotation keeps old service for 1h transition before cleanup - R14: Replace .parse().unwrap() with .unwrap_or(localhost) in rate limiter - R15: Replace 7 unwrap/expect in mesh protocol with proper error propagation - R27: Add 10s timeouts to mesh Bitcoin RPC calls Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -182,6 +182,9 @@ impl RpcHandler {
|
||||
}
|
||||
|
||||
/// Rotate a hidden service's .onion address by generating a new keypair.
|
||||
/// Renames the old hidden service directory (preserving keys during transition),
|
||||
/// lets Tor create a new one with fresh keys, then schedules cleanup of the old
|
||||
/// directory after 1 hour.
|
||||
pub(super) async fn handle_tor_rotate_service(
|
||||
&self,
|
||||
params: Option<serde_json::Value>,
|
||||
@@ -199,11 +202,21 @@ impl RpcHandler {
|
||||
return Err(anyhow::anyhow!("Service '{}' has no .onion address to rotate", name));
|
||||
}
|
||||
|
||||
// Delete old service directory immediately — no transition period
|
||||
delete_hidden_service_dir(name).await;
|
||||
// Rename old service directory to a timestamped backup instead of deleting
|
||||
// immediately. The cleanup handler removes these after ROTATION_TRANSITION_SECS.
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
rename_hidden_service_dir(name, timestamp).await;
|
||||
|
||||
info!(service = name, old_onion = ?old_onion, "Rotated Tor service — restarting Tor");
|
||||
info!(
|
||||
service = name,
|
||||
old_onion = ?old_onion,
|
||||
"Renamed old Tor service dir — restarting Tor to generate new keypair"
|
||||
);
|
||||
|
||||
// Tor restart will create a fresh hidden_service_{name} directory with new keys
|
||||
restart_tor().await?;
|
||||
|
||||
// Wait up to 60s for new hostname file to appear
|
||||
@@ -213,6 +226,14 @@ impl RpcHandler {
|
||||
sync_single_hostname(name, new_addr).await;
|
||||
}
|
||||
|
||||
// Schedule deletion of old service directory after 1 hour transition period
|
||||
let old_name = format!("{}_old_{}", name, timestamp);
|
||||
tokio::spawn(async move {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(3600)).await;
|
||||
info!(old_dir = %old_name, "Transition period elapsed — deleting old Tor service dir");
|
||||
delete_hidden_service_dir(&old_name).await;
|
||||
});
|
||||
|
||||
// Notify federation peers of address change (private peer-to-peer, no public relays)
|
||||
if let Some(ref new_addr) = new_onion {
|
||||
let data_dir = self.config.data_dir.clone();
|
||||
@@ -450,6 +471,18 @@ async fn delete_hidden_service_dir(name: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Rename a hidden service directory to a timestamped backup via tor-helper.
|
||||
/// The old directory becomes `hidden_service_{name}_old_{timestamp}`.
|
||||
async fn rename_hidden_service_dir(name: &str, timestamp: u64) {
|
||||
if let Err(e) = dispatch_tor_action(serde_json::json!({
|
||||
"action": "rename-service",
|
||||
"name": name,
|
||||
"timestamp": timestamp,
|
||||
})).await {
|
||||
warn!("Failed to rename hidden service dir for {}: {}", name, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write staged torrc and restart Tor.
|
||||
async fn restart_tor() -> Result<()> {
|
||||
dispatch_tor_action(serde_json::json!({
|
||||
|
||||
Reference in New Issue
Block a user