Compare commits
1 commit
main
...
wip/arti-h
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcd458ab53 |
2 changed files with 59 additions and 13 deletions
59
src/hs.rs
59
src/hs.rs
|
|
@ -12,14 +12,30 @@ use tor_hsservice::{HsNickname, OnionServiceConfig, RunningOnionService};
|
||||||
use tor_rtcompat::PreferredRuntime;
|
use tor_rtcompat::PreferredRuntime;
|
||||||
|
|
||||||
pub const HS_PORT: u16 = 80;
|
pub const HS_PORT: u16 = 80;
|
||||||
|
/// Ceiling for waiting on `Running` / `DegradedReachable`.
|
||||||
|
///
|
||||||
|
/// Arti's per-HsDir upload timeout is 5 minutes, and circuit timeouts keep
|
||||||
|
/// the combined status at `Bootstrapping` well past 3 minutes. Keep this
|
||||||
|
/// at or above 360s so first publish can finish.
|
||||||
|
pub const PUBLISH_WAIT: Duration = Duration::from_secs(420);
|
||||||
|
/// Floor for Arti circuit-build timeout (ms). Learned CBT on this host
|
||||||
|
/// dropped to ~1s, which CircTimeouts every HsDir descriptor upload.
|
||||||
|
pub const CBT_MIN_TIMEOUT_MSEC: i32 = 10_000;
|
||||||
|
|
||||||
pub type Client = Arc<TorClient<PreferredRuntime>>;
|
pub type Client = Arc<TorClient<PreferredRuntime>>;
|
||||||
|
|
||||||
|
fn apply_net_overrides(builder: &mut TorClientConfigBuilder) {
|
||||||
|
builder
|
||||||
|
.override_net_params()
|
||||||
|
.insert("cbtmintimeout".to_string(), CBT_MIN_TIMEOUT_MSEC);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn client_config(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> TorClientConfig {
|
pub fn client_config(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> TorClientConfig {
|
||||||
std::fs::create_dir_all(state_dir).expect("state dir");
|
std::fs::create_dir_all(state_dir).expect("state dir");
|
||||||
std::fs::create_dir_all(cache_dir).expect("cache dir");
|
std::fs::create_dir_all(cache_dir).expect("cache dir");
|
||||||
let mut builder = TorClientConfigBuilder::from_directories(state_dir, cache_dir);
|
let mut builder = TorClientConfigBuilder::from_directories(state_dir, cache_dir);
|
||||||
builder.storage().permissions().dangerously_trust_everyone();
|
builder.storage().permissions().dangerously_trust_everyone();
|
||||||
|
apply_net_overrides(&mut builder);
|
||||||
builder.build().expect("TorClientConfig")
|
builder.build().expect("TorClientConfig")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,11 +65,17 @@ pub fn onion_string(svc: &RunningOnionService) -> Result<String, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn wait_until_published(svc: &RunningOnionService, label: &str) -> Result<(), String> {
|
pub async fn wait_until_published(svc: &RunningOnionService, label: &str) -> Result<(), String> {
|
||||||
let deadline = Instant::now() + Duration::from_secs(180);
|
let started = Instant::now();
|
||||||
|
let deadline = started + PUBLISH_WAIT;
|
||||||
let mut events = svc.status_events();
|
let mut events = svc.status_events();
|
||||||
loop {
|
loop {
|
||||||
let st = svc.status();
|
let st = svc.status();
|
||||||
eprintln!("{label} hs status: {:?}", st.state());
|
eprintln!(
|
||||||
|
"{label} hs status: {:?} ({:.0}s/{}s)",
|
||||||
|
st.state(),
|
||||||
|
started.elapsed().as_secs_f32(),
|
||||||
|
PUBLISH_WAIT.as_secs()
|
||||||
|
);
|
||||||
match st.state() {
|
match st.state() {
|
||||||
State::Running | State::DegradedReachable => return Ok(()),
|
State::Running | State::DegradedReachable => return Ok(()),
|
||||||
State::Broken => {
|
State::Broken => {
|
||||||
|
|
@ -66,8 +88,10 @@ pub async fn wait_until_published(svc: &RunningOnionService, label: &str) -> Res
|
||||||
}
|
}
|
||||||
if Instant::now() >= deadline {
|
if Instant::now() >= deadline {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"{label}: onion service did not publish within 180s: {:?}",
|
"{label}: onion service did not publish within {}s: {:?} problem={:?}",
|
||||||
st.state()
|
PUBLISH_WAIT.as_secs(),
|
||||||
|
st.state(),
|
||||||
|
st.current_problem()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|
@ -76,3 +100,30 @@ pub async fn wait_until_published(svc: &RunningOnionService, label: &str) -> Res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn publish_wait_covers_hsdir_upload_retries() {
|
||||||
|
assert!(
|
||||||
|
PUBLISH_WAIT >= Duration::from_secs(360),
|
||||||
|
"HsDir circuit timeouts can keep Bootstrapping ~6min before DegradedReachable"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cbt_min_timeout_overrides_learned_subsecond_estimate() {
|
||||||
|
let mut builder = TorClientConfigBuilder::from_directories("/tmp/ow-a", "/tmp/ow-b");
|
||||||
|
apply_net_overrides(&mut builder);
|
||||||
|
assert_eq!(
|
||||||
|
builder.override_net_params().get("cbtmintimeout"),
|
||||||
|
Some(&CBT_MIN_TIMEOUT_MSEC)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
CBT_MIN_TIMEOUT_MSEC >= 10_000,
|
||||||
|
"learned current_timeout was 998ms; HsDir uploads need a multi-second floor"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use arti_client::config::TorClientConfigBuilder;
|
|
||||||
use arti_client::{DormantMode, TorClient, TorClientConfig};
|
use arti_client::{DormantMode, TorClient, TorClientConfig};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
@ -23,12 +22,7 @@ const BOOTSTRAP_LOG: &str = "info";
|
||||||
type Client = Arc<TorClient<PreferredRuntime>>;
|
type Client = Arc<TorClient<PreferredRuntime>>;
|
||||||
|
|
||||||
fn client_config(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> TorClientConfig {
|
fn client_config(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> TorClientConfig {
|
||||||
std::fs::create_dir_all(state_dir).expect("state dir");
|
onionwire::hs::client_config(state_dir, cache_dir)
|
||||||
std::fs::create_dir_all(cache_dir).expect("cache dir");
|
|
||||||
let mut builder = TorClientConfigBuilder::from_directories(state_dir, cache_dir);
|
|
||||||
// Temp dirs sit under $TMP; skip fs-mistrust on the parent tree.
|
|
||||||
builder.storage().permissions().dangerously_trust_everyone();
|
|
||||||
builder.build().expect("TorClientConfig")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn bootstrapped(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> Client {
|
async fn bootstrapped(state_dir: &std::path::Path, cache_dir: &std::path::Path) -> Client {
|
||||||
|
|
@ -89,7 +83,7 @@ async fn launch_echo(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_until_published(svc: &RunningOnionService, label: &str) {
|
async fn wait_until_published(svc: &RunningOnionService, label: &str) {
|
||||||
let deadline = Instant::now() + Duration::from_secs(180);
|
let deadline = Instant::now() + onionwire::hs::PUBLISH_WAIT;
|
||||||
let mut events = svc.status_events();
|
let mut events = svc.status_events();
|
||||||
loop {
|
loop {
|
||||||
let st = svc.status();
|
let st = svc.status();
|
||||||
|
|
@ -103,7 +97,8 @@ async fn wait_until_published(svc: &RunningOnionService, label: &str) {
|
||||||
}
|
}
|
||||||
if Instant::now() >= deadline {
|
if Instant::now() >= deadline {
|
||||||
panic!(
|
panic!(
|
||||||
"{label}: onion service did not publish within 180s: {:?}",
|
"{label}: onion service did not publish within {}s: {:?}",
|
||||||
|
onionwire::hs::PUBLISH_WAIT.as_secs(),
|
||||||
st.state()
|
st.state()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue