tor: fix connection with multiple bridges

This commit is contained in:
ardocrat
2026-03-24 02:13:08 +03:00
parent 26debcf51c
commit 9b6252de3a
4 changed files with 60 additions and 39 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ uuid = { version = "0.8.2", features = ["v4"] }
num-bigint = "0.4.6"
## tor
arti-client = { version = "0.38.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client"] }
arti-client = { version = "0.38.0", features = ["pt-client", "static", "onion-service-service", "onion-service-client", "experimental-api", "bridge-client"] }
tor-rtcompat = { version = "0.38.0", features = ["static"] }
tor-config = "0.38.0"
fs-mistrust = "0.13.1"
-1
View File
@@ -47,7 +47,6 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
#[cfg(debug_assertions)]
{
std::env::set_var("RUST_BACKTRACE", "full");
let log_config = android_logger::Config::default()
+58 -36
View File
@@ -100,22 +100,26 @@ impl Default for Tor {
}
impl Tor {
/// Create Tor client configuration.
fn build_config(bridges: Option<Vec<TorBridge>>) -> TorClientConfig {
/// Create Tor configuration returning unused bridges (exclude more than 2 to avoid stuck).
fn build_config(bridges: Option<Vec<TorBridge>>) -> (TorClientConfig, Vec<TorBridge>) {
let mut builder = TorClientConfigBuilder::from_directories(
TorConfig::state_path(),
TorConfig::cache_path(),
);
// Build bridges.
if let Some(brs) = bridges {
for b in brs {
Self::build_bridge(&mut builder, b);
}
let bridges = bridges.unwrap_or(vec![]);
let max_two_bridges = if bridges.len() > 2 {
bridges.iter().take(2).map(|b| b.clone()).collect::<Vec<TorBridge>>()
} else {
bridges.clone()
};
for b in max_two_bridges {
Self::build_bridge(&mut builder, b);
}
builder.address_filter().allow_onion_addrs(true);
// Create config.
let config = builder.build().unwrap();
config
(config, bridges.iter().map(|b| b.clone()).collect::<Vec<TorBridge>>())
}
/// Build bootstrapped client from provided config.
@@ -163,9 +167,13 @@ impl Tor {
return;
}
}
// Cleanup keys, state and cache.
fs::remove_dir_all(TorConfig::keystore_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
TOR_STATE.client_launching.store(true, Ordering::Relaxed);
// Setup config.
let config = if let Some(b) = TorConfig::get_bridge() {
// Get initial bridges.
let initial_bridges = if let Some(b) = TorConfig::get_bridge() {
let lines_parse = serde_json::from_str::<Vec<String>>(&b.connection_line());
let bridges = if let Ok(lines) = lines_parse {
lines.iter()
@@ -176,37 +184,51 @@ impl Tor {
.map(|l| TorBridge::Webtunnel(b.binary_path(), l.to_string()))
.collect()
};
Self::build_config(Some(bridges))
Some(bridges)
} else {
Self::build_config(None)
None
};
// Launch client.
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
TOR_STATE.client_config.write().replace((c, config));
thread::sleep(Duration::from_millis(5000));
TOR_STATE.client_launching.store(false, Ordering::Relaxed);
} else {
// Launch client with default Webtunnel bridges if failed.
let add_bridges = TorBridge::DEFAULT_WEBTUNNEL_CONN_LINES.iter()
.map(|b| TorBridge::Webtunnel(TorConfig::webtunnel_path(), b.to_string()))
.collect::<Vec<_>>();
let config = Self::build_config(Some(add_bridges));
// Bootstrap client in the loop, trying different bridges.
let mut default_attempt = false;
let mut config_bridges = Self::build_config(initial_bridges);
loop {
let (config, unused_bridges) = config_bridges.clone();
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
TOR_STATE.client_config.write().replace((c, config));
thread::sleep(Duration::from_millis(5000));
TOR_STATE.client_launching.store(false, Ordering::Relaxed);
} else if TorConfig::get_bridge().is_some() {
// Launch without bridges if all attempts failed.
let config = Self::build_config(None);
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
TOR_STATE.client_config.write().replace((c, config));
thread::sleep(Duration::from_millis(5000));
TOR_STATE.client_config.write().replace((c, config.clone()));
break;
} else {
if !unused_bridges.is_empty() {
config_bridges = Self::build_config(Some(unused_bridges));
continue;
}
// Cleanup state and cache.
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
if !default_attempt {
default_attempt = true;
// Launch client with default Webtunnel bridges if failed.
let add_bridges = TorBridge::DEFAULT_WEBTUNNEL_CONN_LINES.iter()
.map(|b| TorBridge::Webtunnel(TorConfig::webtunnel_path(), b.to_string()))
.collect::<Vec<_>>();
config_bridges = Self::build_config(Some(add_bridges));
continue;
} else if TorConfig::get_bridge().is_some() {
// Cleanup state and cache.
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
// Launch without bridges if all attempts failed.
let (config, _) = Self::build_config(None);
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
TOR_STATE.client_config.write().replace((c, config));
}
break;
}
}
}
};
// Wait 5s after launch.
thread::sleep(Duration::from_millis(5000));
TOR_STATE.client_launching.store(false, Ordering::Relaxed);
}
@@ -362,8 +384,8 @@ impl Tor {
// Save failed services if client was not created.
if Self::client_config().is_none() {
for id in service_ids {
let mut w_services = TOR_STATE.fail.write();
w_services.insert(id);
TOR_STATE.start.write().remove(&id);
TOR_STATE.fail.write().insert(id);
}
return;
}
+1 -1
View File
@@ -63,7 +63,7 @@ impl TorBridge {
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_2: &'static str = "webtunnel [2001:db8:eedb:cae7:a345:4f72:f9cc:5de0]:443 B3C81E7A0CA474270DAA4A2C8633E1CA8935C37D url=https://wordpress.far-east-investment.ru/sORes7268CEUSRD7hAWvJU5A ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_3: &'static str = "webtunnel [2001:db8:945c:e0b9:7e4c:c974:ff00:d4c5]:443 91937F3EFB3BE5169788AC7C8BF07460B7E306DB url=https://kabel.entreri.de/YXbp1dNrJeOF8giAFFYWxvmf ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_4: &'static str = "webtunnel [2001:db8:4767:7aa2:df21:1b2b:d7f9:caee]:443 CD193CF0D0C29551928C01FCB28D1200D9F27CFA url=https://occurrence.pics/68SzSlQCRgnfSo32eLyjC1V3 ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:4c9a:ffe8:70f8:d5af:a8f1:cf56]:443 DA1ECF055635C1A6ED7F5B5F36296A5E3015CE57 url=https://1axfa6xb.xoomlia.com/6qtxxkjw/ ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:ce90:3593:272e:4975:a031:55b]:443 12382A2F3912AD1983A97C8709CBAE47ADB60BE3 url=https://miranda.today/LWwxIXDHCyyScn7oDauPMTmX ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_6: &'static str = "webtunnel [2001:db8:a12b:ff8:8a1a:a05b:5f21:2ccc]:443 F2A9C5AEE0A420EB9D55F9497B3C0FA243A2A770 url=https://bridge.lovecloud.me/wss-wc3p0euqrlne98t9 ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_7: &'static str = "webtunnel [2001:db8:8ed6:e6c9:5fc9:9f20:a373:2374]:443 1636A2EFFBAA4B162F5FF461A1663EB55C41AE11 url=https://hanoi.delivery/roQFPLtlspWT6yIKeXD6lEci ver=0.0.3";