diff options
Diffstat (limited to 'crates/tor-circmgr/src')
| -rw-r--r-- | crates/tor-circmgr/src/hspool.rs | 67 | ||||
| -rw-r--r-- | crates/tor-circmgr/src/path/hspath.rs | 53 |
2 files changed, 98 insertions, 22 deletions
diff --git a/crates/tor-circmgr/src/hspool.rs b/crates/tor-circmgr/src/hspool.rs index ace838e22..6622c7307 100644 --- a/crates/tor-circmgr/src/hspool.rs +++ b/crates/tor-circmgr/src/hspool.rs @@ -15,10 +15,10 @@ use futures::{task::SpawnExt, StreamExt, TryFutureExt}; use once_cell::sync::OnceCell; use tor_error::debug_report; use tor_error::{bad_api_usage, internal}; -use tor_linkspec::{CircTarget, OwnedCircTarget}; +use tor_linkspec::{CircTarget, HasRelayIds as _, OwnedCircTarget, RelayIdSet}; use tor_netdir::{NetDir, NetDirProvider, Relay}; -use tor_proto::circuit::{self, ClientCirc}; -use tor_relay_selection::{LowLevelRelayPredicate, RelayExclusion}; +use tor_proto::circuit::{self, CircParameters, ClientCirc}; +use tor_relay_selection::{LowLevelRelayPredicate, RelayExclusion, RelaySelector, RelayUsage}; use tor_rtcompat::{ scheduler::{TaskHandle, TaskSchedule}, Runtime, SleepProviderExt, @@ -304,6 +304,20 @@ impl<R: Runtime> HsCircPool<R> { .into()); } + let params = crate::DirInfo::from(netdir).circ_params(); + self.extend_circ(circ, params, target).await + } + + /// Try to extend a circuit to the specified target hop. + async fn extend_circ<T>( + &self, + circ: HsCircStub, + params: CircParameters, + target: T, + ) -> Result<Arc<ClientCirc>> + where + T: CircTarget, + { // Estimate how long it will take to extend it one more hop, and // construct a timeout as appropriate. let n_hops = circ.n_hops(); @@ -315,7 +329,6 @@ impl<R: Runtime> HsCircPool<R> { ); // Make a future to extend the circuit. - let params = crate::DirInfo::from(netdir).circ_params(); let extend_future = circ .extend_ntor(&target, ¶ms) .map_err(|error| Error::Protocol { @@ -425,7 +438,7 @@ impl<R: Runtime> HsCircPool<R> { }; // Return the circuit we found before, if any. if let Some(circuit) = found_usable_circ { - return self.maybe_extend_stub_circuit(circuit, kind); + return self.maybe_extend_stub_circuit(netdir, circuit, kind).await; } // TODO: There is a possible optimization here. Instead of only waiting @@ -443,9 +456,10 @@ impl<R: Runtime> HsCircPool<R> { } /// Return a circuit of the specified `kind`, built from `circuit`. - fn maybe_extend_stub_circuit( + async fn maybe_extend_stub_circuit( &self, - mut circuit: HsCircStub, + netdir: &NetDir, + circuit: HsCircStub, kind: HsCircStubKind, ) -> Result<HsCircStub> { if !self.vanguards_enabled() { @@ -454,16 +468,49 @@ impl<R: Runtime> HsCircPool<R> { match (circuit.kind, kind) { (HsCircStubKind::Stub, HsCircStubKind::Extended) => { - // TODO HS-VANGUARDS: if full vanguards are enabled and the circuit we got is STUB, + debug!("Wanted STUB+ circuit, but got STUB; extending by 1 hop..."); + let params = CircParameters::default(); + let usage = RelayUsage::middle_relay(Some(&RelayUsage::middle_relay(None))); + let circ_path = circuit.circ.path_ref(); + + // A STUB circuit is a 3-hop circuit. + debug_assert_eq!(circ_path.hops().len(), 3); + + // Like in VanguardHsPathBuilder::pick_path, we only want to exclude the L2 and L3 + // guards (so we skip over the guard) + let skip_n = 1; + let mut exclude_ids = RelayIdSet::new(); + for hop in circ_path + .iter() + .skip(skip_n) + .flat_map(|hop| hop.as_chan_target()) + { + exclude_ids.extend(hop.identities().map(|id| id.to_owned())); + } + + let exclusion = RelayExclusion::exclude_identities(exclude_ids); + let selector = RelaySelector::new(usage, exclusion); + let target = { + let mut rng = rand::thread_rng(); + let (relay, info) = selector.select_relay(&mut rng, netdir); + relay.ok_or_else(|| Error::NoRelay { + path_kind: "vanguard STUB+", + role: "final hop", + problem: info.to_string(), + })? + }; + + // If full vanguards are enabled and the circuit we got is STUB, // we need to extend it by another hop to make it STUB+ before returning it - circuit.kind = kind; + let circ = self.extend_circ(circuit, params, target).await?; - Ok(circuit) + Ok(HsCircStub { circ, kind }) } (HsCircStubKind::Extended, HsCircStubKind::Stub) => { Err(internal!("wanted a STUB circuit, but got STUB+?!").into()) } _ => { + trace!("Wanted {kind} circuit, got {}", circuit.kind); // Nothing to do: the circuit stub we got is of the kind we wanted Ok(circuit) } diff --git a/crates/tor-circmgr/src/path/hspath.rs b/crates/tor-circmgr/src/path/hspath.rs index c9ec30fd8..c3e3e3bb9 100644 --- a/crates/tor-circmgr/src/path/hspath.rs +++ b/crates/tor-circmgr/src/path/hspath.rs @@ -43,9 +43,12 @@ // TODO (#1339): we should be consistent with our terminology. use rand::Rng; +use tor_error::internal; use tor_linkspec::OwnedChanTarget; use tor_netdir::{NetDir, Relay}; -use tor_relay_selection::{RelayExclusion, RelaySelectionConfig, RelaySelector, RelayUsage}; +use tor_relay_selection::{ + RelayExclusion, RelaySelectionConfig, RelaySelector, RelayUsage, SelectionInfo, +}; use crate::{hspool::HsCircStubKind, Error, Result}; @@ -222,13 +225,20 @@ impl VanguardHsPathBuilder { // * the L2 vanguard, because it cannot be selected again as an L3 vanguard // (a relay won't let you extend the circuit to itself). // * the guard, because relays won't let you extend the circuit to their previous hop - let neighbor_exclusion = exclude_identities(&[&l2_guard, &l1_guard]); + let l1_l2_exclusion = exclude_identities(&[&l2_guard, &l1_guard]); let mut hops = vec![l1_guard, l2_guard.clone()]; + let mode = vanguards.mode(); + + let extra_hop_err = |info: SelectionInfo| Error::NoRelay { + path_kind: self.path_kind(), + role: "extra hop", + problem: info.to_string(), + }; // If needed, select an L3 vanguard too - if vanguards.mode() == VanguardMode::Full { + if mode == VanguardMode::Full { let l3_guard: MaybeOwnedRelay = vanguards - .select_vanguard(rng, netdir, Layer::Layer3, &neighbor_exclusion)? + .select_vanguard(rng, netdir, Layer::Layer3, &l1_l2_exclusion)? .into(); hops.push(l3_guard.clone()); @@ -239,22 +249,41 @@ impl VanguardHsPathBuilder { // TODO: this usage has need_stable = true, but we probably // don't necessarily need a stable relay here. let usage = RelayUsage::middle_relay(None); - let neighbor_exclusion = exclude_identities(&[&l2_guard, &l3_guard]); + let l2_l3_exclusion = exclude_identities(&[&l2_guard, &l3_guard]); // We exclude // * the L3 vanguard, because it cannot be selected again as the following // extra hop (a relay won't let you extend the circuit to itself). // * the L2 vanguard, because relays won't let you extend the circuit to their previous hop - let selector = RelaySelector::new(usage, neighbor_exclusion); + let selector = RelaySelector::new(usage, l2_l3_exclusion); let (extra_hop, info) = selector.select_relay(rng, netdir); - let extra_hop = extra_hop.ok_or_else(|| Error::NoRelay { - path_kind: self.path_kind(), - role: "extra hop", - problem: info.to_string(), - })?; - + let extra_hop = extra_hop.ok_or_else(|| extra_hop_err(info))?; hops.push(MaybeOwnedRelay::from(extra_hop)); } + } else { + // Extend the circuit to a third, arbitrarily chosen hop, excluding the L1 and L2 + // guards as before. + let usage = RelayUsage::middle_relay(None); + let selector = RelaySelector::new(usage, l1_l2_exclusion); + + let (extra_hop, info) = selector.select_relay(rng, netdir); + let extra_hop = extra_hop.ok_or_else(|| extra_hop_err(info))?; + hops.push(MaybeOwnedRelay::from(extra_hop)); + } + + match (mode, self.0) { + (VanguardMode::Lite, _) => debug_assert_eq!(hops.len(), 3), + (VanguardMode::Full, HsCircStubKind::Stub) => debug_assert_eq!(hops.len(), 3), + (VanguardMode::Full, HsCircStubKind::Extended) => debug_assert_eq!(hops.len(), 4), + (VanguardMode::Disabled, _) => { + return Err(internal!( + "Called VanguardHsPathBuilder::pick_path(), but vanguards are disabled?!" + ) + .into()); + } + (_, _) => { + return Err(internal!("Unsupported vanguard mode {mode}").into()); + } } Ok((TorPath::new_multihop_from_maybe_owned(hops), mon, usable)) |
