1use std::collections::BTreeMap;
3use std::convert::From;
4use std::default::Default;
5use std::net::{IpAddr, SocketAddr, TcpListener};
6use std::option::Option;
7use std::path::PathBuf;
8use std::str::FromStr;
9use std::string::ToString;
10use std::sync::{atomic, Arc, Mutex};
11use std::time::Duration;
12
13use socks::Socks5Stream;
15use zeroize::ZeroizeOnDrop;
16
17use crate::censorship_circumvention::*;
19use crate::legacy_tor_control_stream::*;
20use crate::legacy_tor_controller::*;
21use crate::legacy_tor_process::*;
22use crate::legacy_tor_version::*;
23use crate::proxy::*;
24use crate::tor_crypto::*;
25use crate::tor_provider;
26use crate::tor_provider::*;
27
28#[derive(thiserror::Error, Debug)]
30pub enum Error {
31 #[error("failed to create LegacyTorProcess object")]
32 LegacyTorProcessCreationFailed(#[source] crate::legacy_tor_process::Error),
33
34 #[error("failed to create LegacyControlStream object")]
35 LegacyControlStreamCreationFailed(#[source] crate::legacy_tor_control_stream::Error),
36
37 #[error("failed to create LegacyTorController object")]
38 LegacyTorControllerCreationFailed(#[source] crate::legacy_tor_controller::Error),
39
40 #[error("failed to authenticate with the tor process")]
41 LegacyTorProcessAuthenticationFailed(#[source] crate::legacy_tor_controller::Error),
42
43 #[error("failed to determine the tor process version")]
44 GetInfoVersionFailed(#[source] crate::legacy_tor_controller::Error),
45
46 #[error("tor process version to old; found {0} but must be at least {1}")]
47 LegacyTorProcessTooOld(String, String),
48
49 #[error("failed to register for STATUS_CLIENT and HS_DESC events")]
50 SetEventsFailed(#[source] crate::legacy_tor_controller::Error),
51
52 #[error("failed to delete unused onion service")]
53 DelOnionFailed(#[source] crate::legacy_tor_controller::Error),
54
55 #[error("failed waiting for async events: {0}")]
56 WaitAsyncEventsFailed(#[source] crate::legacy_tor_controller::Error),
57
58 #[error("failed to begin bootstrap")]
59 SetConfDisableNetwork0Failed(#[source] crate::legacy_tor_controller::Error),
60
61 #[error("failed to setconf")]
62 SetConfFailed(#[source] crate::legacy_tor_controller::Error),
63
64 #[error("failed to add client auth for onion service")]
65 OnionClientAuthAddFailed(#[source] crate::legacy_tor_controller::Error),
66
67 #[error("failed to remove client auth from onion service")]
68 OnionClientAuthRemoveFailed(#[source] crate::legacy_tor_controller::Error),
69
70 #[error("failed to get socks listener")]
71 GetInfoNetListenersSocksFailed(#[source] crate::legacy_tor_controller::Error),
72
73 #[error("no socks listeners available to connect through")]
74 NoSocksListenersFound(),
75
76 #[error("invalid circuit token")]
77 CircuitTokenInvalid(),
78
79 #[error("unable to connect to socks listener")]
80 Socks5ConnectionFailed(#[source] std::io::Error),
81
82 #[error("failed to spawn connect_async thread")]
83 ConnectAsyncThreadSpawnFailed(#[source] std::io::Error),
84
85 #[error("unable to bind TCP listener")]
86 TcpListenerBindFailed(#[source] std::io::Error),
87
88 #[error("unable to get TCP listener's local address")]
89 TcpListenerLocalAddrFailed(#[source] std::io::Error),
90
91 #[error("failed to create onion service")]
92 AddOnionFailed(#[source] crate::legacy_tor_controller::Error),
93
94 #[error("tor not bootstrapped")]
95 LegacyTorNotBootstrapped(),
96
97 #[error("{0}")]
98 PluggableTransportConfigDirectoryCreationFailed(#[source] std::io::Error),
99
100 #[error("unable to create pluggable-transport directory because file with same name already exists: {0:?}")]
101 PluggableTransportDirectoryNameCollision(PathBuf),
102
103 #[error("{0}")]
104 PluggableTransportSymlinkRemovalFailed(#[source] std::io::Error),
105
106 #[error("{0}")]
107 PluggableTransportSymlinkCreationFailed(#[source] std::io::Error),
108
109 #[error("pluggable transport binary name not representable as utf8: {0:?}")]
110 PluggableTransportBinaryNameNotUtf8Representnable(std::ffi::OsString),
111
112 #[error("{0}")]
113 PluggableTransportConfigError(#[source] crate::censorship_circumvention::PluggableTransportConfigError),
114
115 #[error("pluggable transport multiply defines '{0}' bridge transport type")]
116 BridgeTransportTypeMultiplyDefined(String),
117
118 #[error("bridge transport '{0}' not supported by pluggable transport configuration")]
119 BridgeTransportNotSupported(String),
120
121 #[error("invalid environment variable configuration: {0}")]
122 EnvironmentConfigurationInvalid(String),
123
124 #[error("not implemented")]
125 NotImplemented(),
126}
127
128impl From<Error> for crate::tor_provider::Error {
129 fn from(error: Error) -> Self {
130 crate::tor_provider::Error::Generic(error.to_string())
131 }
132}
133
134struct LegacyCircuitToken {
138 username: String,
139 password: String,
140}
141
142impl LegacyCircuitToken {
143 fn new() -> LegacyCircuitToken {
144 const CIRCUIT_TOKEN_USERNAME_LENGTH: usize = 32usize;
145 const CIRCUIT_TOKEN_PASSWORD_LENGTH: usize = 32usize;
146 let username = generate_password(CIRCUIT_TOKEN_USERNAME_LENGTH);
147 let password = generate_password(CIRCUIT_TOKEN_PASSWORD_LENGTH);
148
149 LegacyCircuitToken { username, password }
150 }
151}
152
153impl Default for LegacyCircuitToken {
154 fn default() -> Self {
155 Self::new()
156 }
157}
158
159#[derive(Clone, Debug)]
164pub enum LegacyTorClientConfig {
165 BundledTor {
166 tor_bin_path: PathBuf,
167 data_directory: PathBuf,
168 proxy_settings: Option<ProxyConfig>,
169 allowed_ports: Option<Vec<u16>>,
170 pluggable_transports: Option<Vec<PluggableTransportConfig>>,
171 bridge_lines: Option<Vec<BridgeLine>>,
172 },
173 SystemTor {
174 tor_socks_addr: SocketAddr,
175 tor_control_addr: SocketAddr,
176 tor_control_auth: TorAuth,
177 },
178}
179
180impl LegacyTorClientConfig {
181 pub fn try_from_environment() -> Result<Self, Error> {
184 use std::env::{var, var_os};
185
186 const TOR_SOCKS_HOST: &str = "TOR_SOCKS_HOST";
188 const TOR_SOCKS_PORT: &str = "TOR_SOCKS_PORT";
189 let tor_socks_addr = match (var(TOR_SOCKS_HOST), var(TOR_SOCKS_PORT)) {
190 (Ok(host), Ok(port)) => {
191 let ip = IpAddr::from_str(host.as_str()).map_err(|_| Error::EnvironmentConfigurationInvalid(format!("cannot parse TOR_SOCKS_HOST value '{host}' as ip address")))?;
192 let port = u16::from_str(port.as_str()).map_err(|_| Error::EnvironmentConfigurationInvalid(format!("cannot parse TOR_SOCKS_PORT value '{port}' as port")))?;
193 SocketAddr::new(ip, port)
194 },
195 _ => return Err(Error::EnvironmentConfigurationInvalid("environment variables TOR_SOCKS_HOST and TOR_SOCKS_PORT must be defined".to_string())),
196 };
197
198 const TOR_CONTROL_HOST: &str = "TOR_CONTROL_HOST";
200 const TOR_CONTROL_PORT: &str = "TOR_CONTROL_PORT";
201 let tor_control_addr = match (var(TOR_CONTROL_HOST), var(TOR_CONTROL_PORT)) {
202 (Ok(host), Ok(port)) => {
203 let ip = IpAddr::from_str(host.as_str()).map_err(|_| Error::EnvironmentConfigurationInvalid(format!("cannot parse TOR_CONTROL_HOST value '{host}' as ip address")))?;
204 let port = u16::from_str(port.as_str()).map_err(|_| Error::EnvironmentConfigurationInvalid(format!("cannot parse TOR_CONTROL_PORT value '{port}' as port")))?;
205 SocketAddr::new(ip, port)
206 },
207 _ => return Err(Error::EnvironmentConfigurationInvalid("environment variables TOR_CONTROL_HOST and TOR_CONTROL_PORT must be defined".to_string())),
208 };
209
210 const TOR_CONTROL_COOKIE_AUTH_FILE: &str = "TOR_CONTROL_COOKIE_AUTH_FILE";
212 const TOR_CONTROL_PASSWD: &str = "TOR_CONTROL_PASSWD";
213 let tor_control_auth = if let Some(cookie_file) = var_os(TOR_CONTROL_COOKIE_AUTH_FILE) {
214 let cookie_file: PathBuf = cookie_file.clone().try_into().map_err(|_| Error::EnvironmentConfigurationInvalid(format!("Cannot parse TOR_CONTROL_COOKIE_AUTH_FILE value '{cookie_file:?} as file path")))?;
215 TorAuth::CookieFile(cookie_file)
216 } else {
217 match var(TOR_CONTROL_PASSWD) {
218 Ok(control_password) => TorAuth::Password(control_password),
219 Err(std::env::VarError::NotPresent) => TorAuth::Null,
220 _ => return Err(Error::EnvironmentConfigurationInvalid("Failed to read TOR_CONTROL_PASSWD".to_string())),
221 }
222 };
223
224 Ok(Self::SystemTor{tor_socks_addr, tor_control_addr, tor_control_auth})
225 }
226}
227
228#[derive(Clone, Debug, Default, Eq, PartialEq, ZeroizeOnDrop)]
229pub enum TorAuth {
230 #[default]
231 #[zeroize(skip)]
232 Null,
233 Password(String),
234 #[zeroize(skip)]
235 CookieFile(PathBuf),
236}
237
238pub struct LegacyTorClient {
248 daemon: Option<LegacyTorProcess>,
249 version: LegacyTorVersion,
250 controller: LegacyTorController,
251 bootstrapped: bool,
252 socks_listener: Option<SocketAddr>,
253 async_events: Arc<Mutex<Vec<TorEvent>>>,
254 next_connect_handle: ConnectHandle,
255 onion_services: Vec<(V3OnionServiceId, Arc<atomic::AtomicBool>)>,
257 circuit_token_counter: usize,
259 circuit_tokens: BTreeMap<CircuitToken, LegacyCircuitToken>,
260}
261
262impl LegacyTorClient {
263 pub fn new(mut config: LegacyTorClientConfig) -> Result<LegacyTorClient, Error> {
265 let (daemon, mut controller, mut auth, socks_listener) = match &mut config {
266 LegacyTorClientConfig::BundledTor {
267 tor_bin_path,
268 data_directory,
269 ..
270 } => {
271 let daemon =
273 LegacyTorProcess::new(tor_bin_path.as_path(), data_directory.as_path())
274 .map_err(Error::LegacyTorProcessCreationFailed)?;
275 let control_stream =
277 LegacyControlStream::new(daemon.get_control_addr(), Duration::from_millis(16))
278 .map_err(Error::LegacyControlStreamCreationFailed)?;
279
280 let controller = LegacyTorController::new(control_stream)
282 .map_err(Error::LegacyTorControllerCreationFailed)?;
283
284 let password = daemon.get_password().to_string();
285 (Some(daemon), controller, TorAuth::Password(password), None)
286 }
287 LegacyTorClientConfig::SystemTor {
288 tor_socks_addr,
289 tor_control_addr,
290 tor_control_auth,
291 } => {
292 let control_stream =
294 LegacyControlStream::new(&tor_control_addr, Duration::from_millis(16))
295 .map_err(Error::LegacyControlStreamCreationFailed)?;
296
297 let controller = LegacyTorController::new(control_stream)
299 .map_err(Error::LegacyTorControllerCreationFailed)?;
300
301 (
302 None,
303 controller,
304 std::mem::take(tor_control_auth),
305 Some(tor_socks_addr.clone()),
306 )
307 }
308 };
309
310 match &mut auth {
312 TorAuth::Null => controller.authenticate(),
313 TorAuth::Password(pass) => controller.authenticate_password(std::mem::take(pass)),
314 TorAuth::CookieFile(file) => controller.authenticate_safecookie(std::mem::take(file)),
315 }.map_err(Error::LegacyTorProcessAuthenticationFailed)?;
316
317 let min_required_version = LegacyTorVersion {
319 major: 0u32,
320 minor: 4u32,
321 micro: 6u32,
322 patch_level: 1u32,
323 status_tag: None,
324 };
325
326 let version = controller
328 .getinfo_version()
329 .map_err(Error::GetInfoVersionFailed)?;
330
331 if version < min_required_version {
332 return Err(Error::LegacyTorProcessTooOld(
333 version.to_string(),
334 min_required_version.to_string(),
335 ));
336 }
337
338 if let LegacyTorClientConfig::BundledTor {
340 data_directory,
341 proxy_settings,
342 allowed_ports,
343 pluggable_transports,
344 bridge_lines,
345 ..
346 } = config
347 {
348 match proxy_settings {
350 Some(ProxyConfig::Socks4(Socks4ProxyConfig { address })) => {
351 controller
352 .setconf(&[("Socks4Proxy", address.to_string())])
353 .map_err(Error::SetConfFailed)?;
354 }
355 Some(ProxyConfig::Socks5(Socks5ProxyConfig {
356 address,
357 username,
358 password,
359 })) => {
360 controller
361 .setconf(&[("Socks5Proxy", address.to_string())])
362 .map_err(Error::SetConfFailed)?;
363 let username = username.unwrap_or("".to_string());
364 if !username.is_empty() {
365 controller
366 .setconf(&[("Socks5ProxyUsername", username.to_string())])
367 .map_err(Error::SetConfFailed)?;
368 }
369 let password = password.unwrap_or("".to_string());
370 if !password.is_empty() {
371 controller
372 .setconf(&[("Socks5ProxyPassword", password.to_string())])
373 .map_err(Error::SetConfFailed)?;
374 }
375 }
376 Some(ProxyConfig::Https(HttpsProxyConfig {
377 address,
378 username,
379 password,
380 })) => {
381 controller
382 .setconf(&[("HTTPSProxy", address.to_string())])
383 .map_err(Error::SetConfFailed)?;
384 let username = username.unwrap_or("".to_string());
385 let password = password.unwrap_or("".to_string());
386 if !username.is_empty() || !password.is_empty() {
387 let authenticator = format!("{}:{}", username, password);
388 controller
389 .setconf(&[("HTTPSProxyAuthenticator", authenticator)])
390 .map_err(Error::SetConfFailed)?;
391 }
392 }
393 None => (),
394 }
395 if let Some(allowed_ports) = allowed_ports {
397 let allowed_addresses: Vec<String> = allowed_ports
398 .iter()
399 .map(|port| format!("*{{}}:{port}"))
400 .collect();
401 let allowed_addresses = allowed_addresses.join(", ");
402 controller
403 .setconf(&[("ReachableAddresses", allowed_addresses)])
404 .map_err(Error::SetConfFailed)?;
405 }
406 let mut supported_transports: std::collections::BTreeSet<String> = Default::default();
408 if let Some(pluggable_transports) = pluggable_transports {
409 let mut pt_directory = data_directory.clone();
417 pt_directory.push("pluggable-transports");
418 if !std::path::Path::exists(&pt_directory) {
419 std::fs::create_dir(&pt_directory)
421 .map_err(Error::PluggableTransportConfigDirectoryCreationFailed)?;
422 } else if !std::path::Path::is_dir(&pt_directory) {
423 return Err(Error::PluggableTransportDirectoryNameCollision(
425 pt_directory,
426 ));
427 }
428
429 let mut conf: Vec<(&str, String)> = Default::default();
431 for pt_settings in &pluggable_transports {
432 let path_to_binary = pt_settings.path_to_binary();
435 let binary_name = path_to_binary
436 .file_name()
437 .expect("file_name should be absolute path");
438 let mut pt_symlink = pt_directory.clone();
439 pt_symlink.push(binary_name);
440 let binary_name = if let Some(binary_name) = binary_name.to_str() {
441 binary_name
442 } else {
443 return Err(Error::PluggableTransportBinaryNameNotUtf8Representnable(
444 binary_name.to_os_string(),
445 ));
446 };
447
448 if std::path::Path::exists(&pt_symlink) {
450 std::fs::remove_file(&pt_symlink)
451 .map_err(Error::PluggableTransportSymlinkRemovalFailed)?;
452 }
453
454 #[cfg(windows)]
456 std::os::windows::fs::symlink_file(path_to_binary, &pt_symlink)
457 .map_err(Error::PluggableTransportSymlinkCreationFailed)?;
458 #[cfg(unix)]
459 std::os::unix::fs::symlink(path_to_binary, &pt_symlink)
460 .map_err(Error::PluggableTransportSymlinkCreationFailed)?;
461
462 for transport in pt_settings.transports() {
464 if supported_transports.contains(transport) {
465 return Err(Error::BridgeTransportTypeMultiplyDefined(
466 transport.to_string(),
467 ));
468 }
469 supported_transports.insert(transport.to_string());
470 }
471
472 let transports = pt_settings.transports().join(",");
474 use std::path::MAIN_SEPARATOR;
475 let path_to_binary =
476 format!("pluggable-transports{MAIN_SEPARATOR}{binary_name}");
477 let options = pt_settings.options().join(" ");
478
479 let value = format!("{transports} exec {path_to_binary} {options}");
480 conf.push(("ClientTransportPlugin", value));
481 }
482 controller
483 .setconf(conf.as_slice())
484 .map_err(Error::SetConfFailed)?;
485 }
486 if let Some(bridge_lines) = bridge_lines {
488 let mut conf: Vec<(&str, String)> = Default::default();
489 for bridge_line in &bridge_lines {
490 if !supported_transports.contains(bridge_line.transport()) {
491 return Err(Error::BridgeTransportNotSupported(
492 bridge_line.transport().to_string(),
493 ));
494 }
495 let value = bridge_line.as_legacy_tor_setconf_value();
496 conf.push(("Bridge", value));
497 }
498 conf.push(("UseBridges", "1".to_string()));
499 controller
500 .setconf(conf.as_slice())
501 .map_err(Error::SetConfFailed)?;
502 }
503 }
504
505 controller
507 .setevents(&["STATUS_CLIENT", "HS_DESC"])
508 .map_err(Error::SetEventsFailed)?;
509
510 Ok(LegacyTorClient {
511 daemon,
512 version,
513 controller,
514 bootstrapped: false,
515 socks_listener,
516 onion_services: Default::default(),
517 async_events: Default::default(),
518 next_connect_handle: Default::default(),
519 circuit_token_counter: 0usize,
520 circuit_tokens: Default::default(),
521 })
522 }
523
524 pub fn version(&mut self) -> LegacyTorVersion {
526 self.version.clone()
527 }
528
529 fn socks_listener(&mut self) -> Result<SocketAddr, Error> {
530 match self.socks_listener {
531 Some(socks_listener) => Ok(socks_listener.clone()),
532 None => {
533 let mut listeners = self
534 .controller
535 .getinfo_net_listeners_socks()
536 .map_err(Error::GetInfoNetListenersSocksFailed)?;
537 if listeners.is_empty() {
538 return Err(Error::NoSocksListenersFound())?;
539 }
540 let socks_listener = listeners.swap_remove(0);
541 self.socks_listener = Some(socks_listener.clone());
542 Ok(socks_listener)
543 }
544 }
545 }
546
547 fn connect_impl(
548 target_addr: TargetAddr,
549 socks_listener: SocketAddr,
550 socks_credentials: Option<(String, String)>,
551 ) -> Result<Socks5Stream, tor_provider::Error> {
552 let socks_target = match target_addr {
554 TargetAddr::Socket(socket_addr) => socks::TargetAddr::Ip(socket_addr),
555 TargetAddr::Domain(domain_addr) => {
556 socks::TargetAddr::Domain(domain_addr.domain().to_string(), domain_addr.port())
557 }
558 TargetAddr::OnionService(OnionAddr::V3(OnionAddrV3 {
559 service_id,
560 virt_port,
561 })) => socks::TargetAddr::Domain(format!("{}.onion", service_id), virt_port),
562 };
563
564 let stream = match socks_credentials {
566 None => Socks5Stream::connect(socks_listener, socks_target),
567 Some((username, password)) => Socks5Stream::connect_with_password(
568 socks_listener,
569 socks_target,
570 &username,
571 &password,
572 ),
573 }.map_err(Error::Socks5ConnectionFailed)?;
574 Ok(stream)
575 }
576}
577
578impl TorProvider for LegacyTorClient {
579 fn update(&mut self) -> Result<Vec<TorEvent>, tor_provider::Error> {
580 let mut i = 0;
581 while i < self.onion_services.len() {
582 if !self.onion_services[i].1.load(atomic::Ordering::Relaxed) {
584 let entry = self.onion_services.swap_remove(i);
585 let service_id = entry.0;
586
587 self.controller
588 .del_onion(&service_id)
589 .map_err(Error::DelOnionFailed)?;
590 } else {
591 i += 1;
592 }
593 }
594
595 let mut events: Vec<TorEvent> = Default::default();
596 for async_event in self
597 .controller
598 .wait_async_events()
599 .map_err(Error::WaitAsyncEventsFailed)?
600 {
601 match async_event {
602 AsyncEvent::StatusClient {
603 severity,
604 action,
605 arguments,
606 } => {
607 if severity == "NOTICE" && action == "BOOTSTRAP" {
608 let mut progress: u32 = 0;
609 let mut tag: String = Default::default();
610 let mut summary: String = Default::default();
611 for (key, val) in arguments {
612 match key.as_str() {
613 "PROGRESS" => progress = val.parse().unwrap_or(0u32),
614 "TAG" => tag = val,
615 "SUMMARY" => summary = val,
616 _ => {} }
618 }
619 events.push(TorEvent::BootstrapStatus {
620 progress,
621 tag,
622 summary,
623 });
624 if progress == 100u32 {
625 events.push(TorEvent::BootstrapComplete);
626 self.bootstrapped = true;
627 }
628 }
629 }
630 AsyncEvent::HsDesc { action, hs_address } => {
631 if action == "UPLOADED" {
632 events.push(TorEvent::OnionServicePublished {
633 service_id: hs_address,
634 });
635 }
636 }
637 AsyncEvent::Unknown { lines } => {
638 println!("Received Unknown Event:");
639 for line in lines.iter() {
640 println!(" {}", line);
641 }
642 }
643 }
644 }
645
646 if let Some(daemon) = &mut self.daemon {
647 for log_line in daemon.wait_log_lines().iter_mut() {
649 events.push(TorEvent::LogReceived {
650 line: std::mem::take(log_line),
651 });
652 }
653 } else if !self.bootstrapped {
654 events.push(TorEvent::BootstrapComplete);
656 self.bootstrapped = true;
657 }
658
659 let mut async_events = self.async_events.lock().expect("async_events mutex poisoned");
661 if !async_events.is_empty() {
662 events.append(&mut std::mem::take(&mut *async_events));
663 }
664
665 Ok(events)
666 }
667
668 fn bootstrap(&mut self) -> Result<(), tor_provider::Error> {
669 if !self.bootstrapped {
670 self.controller
671 .setconf(&[("DisableNetwork", "0".to_string())])
672 .map_err(Error::SetConfDisableNetwork0Failed)?;
673 }
674 Ok(())
675 }
676
677 fn add_client_auth(
678 &mut self,
679 service_id: &V3OnionServiceId,
680 client_auth: &X25519PrivateKey,
681 ) -> Result<(), tor_provider::Error> {
682 Ok(self
683 .controller
684 .onion_client_auth_add(service_id, client_auth, None, &Default::default())
685 .map_err(Error::OnionClientAuthAddFailed)?)
686 }
687
688 fn remove_client_auth(
689 &mut self,
690 service_id: &V3OnionServiceId,
691 ) -> Result<(), tor_provider::Error> {
692 Ok(self
693 .controller
694 .onion_client_auth_remove(service_id)
695 .map_err(Error::OnionClientAuthRemoveFailed)?)
696 }
697
698 fn connect(
700 &mut self,
701 target: TargetAddr,
702 circuit: Option<CircuitToken>,
703 ) -> Result<OnionStream, tor_provider::Error> {
704 if !self.bootstrapped {
705 return Err(Error::LegacyTorNotBootstrapped().into());
706 }
707
708 let socks_listener = self.socks_listener()?;
709 let socks_credentials = match circuit {
710 Some(circuit) => if let Some(circuit) = self.circuit_tokens.get(&circuit) {
711 Some((circuit.username.clone(), circuit.password.clone()))
712 } else {
713 return Err(Error::CircuitTokenInvalid())?;
714 },
715 None => None,
716 };
717
718 let stream = Self::connect_impl(target.clone(), socks_listener, socks_credentials)?;
719
720 Ok(OnionStream {
721 stream: stream.into_inner(),
722 local_addr: None,
723 peer_addr: Some(target),
724 })
725 }
726
727 fn connect_async(
728 &mut self,
729 target: TargetAddr,
730 circuit: Option<CircuitToken>,
731 ) -> Result<ConnectHandle, tor_provider::Error> {
732
733 let socks_listener = self.socks_listener()?;
734 let socks_credentials = match circuit {
735 Some(circuit) => if let Some(circuit) = self.circuit_tokens.get(&circuit) {
736 Some((circuit.username.clone(), circuit.password.clone()))
737 } else {
738 return Err(Error::CircuitTokenInvalid())?;
739 },
740 None => None,
741 };
742
743 let handle = self.next_connect_handle;
744 self.next_connect_handle += 1usize;
745
746 let async_events = Arc::downgrade(&self.async_events);
747
748 std::thread::Builder::new()
750 .spawn(move || {
751 let stream = Self::connect_impl(target.clone(), socks_listener, socks_credentials);
752 if let Some(async_events) = async_events.upgrade() {
753 let event = match stream {
754 Ok(stream) => {
755 let stream = OnionStream {
756 stream: stream.into_inner(),
757 local_addr: None,
758 peer_addr: Some(target),
759 };
760 TorEvent::ConnectComplete{
761 handle,
762 stream,
763 }
764 },
765 Err(error) => TorEvent::ConnectFailed{
766 handle,
767 error,
768 },
769 };
770 let mut async_events = async_events.lock().expect("async_events mutex poisoned");
771 async_events.push(event);
772 }
773 }).map_err(Error::ConnectAsyncThreadSpawnFailed)?;
774
775 Ok(handle)
776 }
777
778 fn listener(
780 &mut self,
781 private_key: &Ed25519PrivateKey,
782 virt_port: u16,
783 authorized_clients: Option<&[X25519PublicKey]>,
784 ) -> Result<OnionListener, tor_provider::Error> {
785 if !self.bootstrapped {
786 return Err(Error::LegacyTorNotBootstrapped().into());
787 }
788
789 let socket_addr = SocketAddr::from(([127, 0, 0, 1], 0u16));
791 let listener = TcpListener::bind(socket_addr).map_err(Error::TcpListenerBindFailed)?;
792 let socket_addr = listener
793 .local_addr()
794 .map_err(Error::TcpListenerLocalAddrFailed)?;
795
796 let flags = AddOnionFlags {
797 discard_pk: true,
798 v3_auth: authorized_clients.is_some(),
799 ..Default::default()
800 };
801
802 let onion_addr = OnionAddr::V3(OnionAddrV3::new(
803 V3OnionServiceId::from_private_key(private_key),
804 virt_port,
805 ));
806
807 let (_, service_id) = self
809 .controller
810 .add_onion(
811 Some(private_key),
812 &flags,
813 None,
814 virt_port,
815 Some(socket_addr),
816 authorized_clients,
817 )
818 .map_err(Error::AddOnionFailed)?;
819
820 let is_active = Arc::new(atomic::AtomicBool::new(true));
821 self.onion_services
822 .push((service_id, Arc::clone(&is_active)));
823
824 Ok(OnionListener::new(listener, onion_addr, is_active, |is_active| {
825 is_active.store(false, atomic::Ordering::Relaxed);
826 }))
827 }
828
829 fn generate_token(&mut self) -> CircuitToken {
830 let new_token = self.circuit_token_counter;
831 self.circuit_token_counter += 1;
832 self.circuit_tokens
833 .insert(new_token, LegacyCircuitToken::new());
834 new_token
835 }
836
837 fn release_token(&mut self, circuit_token: CircuitToken) {
838 self.circuit_tokens.remove(&circuit_token);
839 }
840}