Skip to main content

tor_circmgr/
impls.rs

1//! Implement traits from [`crate::mgr`] for the circuit types we use.
2
3use crate::build::TunnelBuilder;
4use crate::mgr::{self, MockablePlan};
5use crate::path::OwnedPath;
6use crate::usage::{SupportedTunnelUsage, TargetTunnelUsage};
7use crate::{DirInfo, Error, PathConfig, Result, timeouts};
8use async_trait::async_trait;
9use educe::Educe;
10use futures::future::OptionFuture;
11use std::sync::Arc;
12use tor_basic_utils::skip_fmt;
13use tor_error::{bad_api_usage, internal};
14#[cfg(feature = "vanguards")]
15use tor_guardmgr::vanguards::VanguardMgr;
16use tor_linkspec::CircTarget;
17use tor_proto::ClientTunnel;
18use tor_proto::circuit::UniqId;
19use tor_proto::client::circuit::{CircParameters, Path};
20use tor_rtcompat::Runtime;
21use tracing::instrument;
22use web_time_compat::Instant;
23
24#[async_trait]
25impl mgr::AbstractTunnel for tor_proto::ClientTunnel {
26    type Id = tor_proto::circuit::UniqId;
27
28    fn id(&self) -> Self::Id {
29        self.unique_id()
30    }
31
32    fn usable(&self) -> bool {
33        !self.is_closing()
34    }
35
36    // TODO: replace Itertools::exactly_one() with a stdlib equivalent when there is one.
37    //
38    // See issue #48919 <https://github.com/rust-lang/rust/issues/48919>
39    #[allow(unstable_name_collisions)]
40    fn single_path(&self) -> tor_proto::Result<Arc<Path>> {
41        use itertools::Itertools as _;
42
43        self.all_paths().into_iter().exactly_one().map_err(|_| {
44            bad_api_usage!("requested the single path of a multi-path tunnel?!").into()
45        })
46    }
47
48    fn n_hops(&self) -> tor_proto::Result<usize> {
49        self.n_hops()
50    }
51
52    fn is_closing(&self) -> bool {
53        self.is_closed()
54    }
55
56    fn unique_id(&self) -> UniqId {
57        self.unique_id()
58    }
59
60    async fn extend<T: CircTarget + Sync>(
61        &self,
62        target: &T,
63        params: CircParameters,
64    ) -> tor_proto::Result<()> {
65        let circ = self.as_single_circ()?;
66        circ.extend(target, params).await
67    }
68
69    async fn last_known_to_be_used_at(&self) -> tor_proto::Result<Option<Instant>> {
70        self.disused_since().await
71    }
72}
73
74/// The information generated by circuit planning, and used to build a
75/// circuit.
76#[derive(Educe)]
77#[educe(Debug)]
78pub(crate) struct Plan {
79    /// The supported usage that the circuit will have when complete
80    final_spec: SupportedTunnelUsage,
81    /// An owned copy of the path to build.
82    // TODO: it would be nice if this weren't owned.
83    path: OwnedPath,
84    /// The protocol parameters to use when constructing the circuit.
85    params: CircParameters,
86    /// If this path is using a guard, we'll use this object to report
87    /// whether the circuit succeeded or failed.
88    guard_status: Option<tor_guardmgr::GuardMonitor>,
89    /// If this path is using a guard, we'll use this object to learn
90    /// whether we're allowed to use the circuit or whether we have to
91    /// wait a while.
92    #[educe(Debug(method = "skip_fmt"))]
93    guard_usable: Option<tor_guardmgr::GuardUsable>,
94}
95
96impl MockablePlan for Plan {}
97
98#[async_trait]
99impl<R: Runtime> crate::mgr::AbstractTunnelBuilder<R> for crate::build::TunnelBuilder<R> {
100    type Tunnel = ClientTunnel;
101    type Plan = Plan;
102
103    #[instrument(level = "trace", skip_all)]
104    fn plan_tunnel(
105        &self,
106        usage: &TargetTunnelUsage,
107        dir: DirInfo<'_>,
108    ) -> Result<(Plan, SupportedTunnelUsage)> {
109        let mut rng = rand::rng();
110        let (path, final_spec, guard_status, guard_usable) = usage.build_path(
111            &mut rng,
112            dir,
113            self.guardmgr(),
114            #[cfg(all(feature = "vanguards", feature = "hs-common"))]
115            self.vanguardmgr(),
116            self.path_config().as_ref(),
117            self.runtime().wallclock(),
118        )?;
119
120        let plan = Plan {
121            final_spec: final_spec.clone(),
122            path: (&path).try_into()?,
123            params: dir.circ_params(usage)?,
124            guard_status,
125            guard_usable,
126        };
127
128        Ok((plan, final_spec))
129    }
130
131    #[instrument(level = "trace", skip_all)]
132    async fn build_tunnel(&self, plan: Plan) -> Result<(SupportedTunnelUsage, Self::Tunnel)> {
133        use crate::build::GuardStatusHandle;
134        use tor_guardmgr::GuardStatus;
135        let Plan {
136            final_spec,
137            path,
138            params,
139            guard_status,
140            guard_usable,
141        } = plan;
142
143        let guard_usable: OptionFuture<_> = guard_usable.into();
144        let guard_status: Arc<GuardStatusHandle> = Arc::new(guard_status.into());
145
146        guard_status.pending(GuardStatus::AttemptAbandoned);
147
148        // TODO: We may want to lower the logic for handling
149        // guard_status and guard_usable into build.rs, so that they
150        // can be handled correctly on user-selected paths as well.
151        //
152        // This will probably require a different API for circuit
153        // construction.
154        match self
155            .build_owned(
156                path,
157                &params,
158                Arc::clone(&guard_status),
159                final_spec.channel_usage(),
160            )
161            .await
162        {
163            Ok(tunnel) => {
164                // Report success to the guard manager, so it knows that
165                // this guard is reachable.
166                guard_status.report(GuardStatus::Success);
167
168                // We have to wait for the guard manager to tell us whether
169                // this guard is actually _usable_ or not.  Possibly,
170                // it is a speculative guard that we're only trying out
171                // in case some preferable guard won't meet our needs.
172                match guard_usable.await {
173                    Some(Ok(true)) | None => (),
174                    Some(Ok(false)) => return Err(Error::GuardNotUsable(tunnel.unique_id())),
175                    Some(Err(_)) => {
176                        return Err(internal!("Guard usability status cancelled").into());
177                    }
178                }
179                Ok((final_spec, tunnel))
180            }
181            Err(e) => {
182                // The attempt failed; the builder should have set the
183                // pending status on the guard to some value which will
184                // tell the guard manager whether to blame the guard or not.
185                guard_status.commit();
186
187                Err(e)
188            }
189        }
190    }
191
192    fn launch_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
193        match spec {
194            TargetTunnelUsage::Dir => 3,
195            _ => 1,
196        }
197    }
198
199    fn select_parallelism(&self, spec: &TargetTunnelUsage) -> usize {
200        self.launch_parallelism(spec)
201    }
202
203    fn learning_timeouts(&self) -> bool {
204        TunnelBuilder::learning_timeouts(self)
205    }
206
207    fn save_state(&self) -> Result<bool> {
208        TunnelBuilder::save_state(self)
209    }
210
211    fn path_config(&self) -> Arc<PathConfig> {
212        TunnelBuilder::path_config(self)
213    }
214
215    fn set_path_config(&self, new_config: PathConfig) {
216        TunnelBuilder::set_path_config(self, new_config);
217    }
218
219    fn estimator(&self) -> &timeouts::Estimator {
220        TunnelBuilder::estimator(self)
221    }
222
223    #[cfg(feature = "vanguards")]
224    fn vanguardmgr(&self) -> &Arc<VanguardMgr<R>> {
225        TunnelBuilder::vanguardmgr(self)
226    }
227
228    #[instrument(level = "trace", skip_all)]
229    fn upgrade_to_owned_state(&self) -> Result<()> {
230        TunnelBuilder::upgrade_to_owned_state(self)
231    }
232
233    #[instrument(level = "trace", skip_all)]
234    fn reload_state(&self) -> Result<()> {
235        TunnelBuilder::reload_state(self)
236    }
237
238    fn guardmgr(&self) -> &tor_guardmgr::GuardMgr<R> {
239        TunnelBuilder::guardmgr(self)
240    }
241
242    fn update_network_parameters(&self, p: &tor_netdir::params::NetParameters) {
243        TunnelBuilder::update_network_parameters(self, p);
244    }
245}