Merge branch 'ipt_to_circtarget' into 'main'
Construct a CircTarget from an IntroPointDesc. See merge request tpo/core/arti!1221
This commit is contained in:
commit
924dbf7d8f
|
@ -4164,6 +4164,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tor-async-utils",
|
||||
"tor-basic-utils",
|
||||
"tor-bytes",
|
||||
"tor-chanmgr",
|
||||
"tor-checkable",
|
||||
"tor-circmgr",
|
||||
|
|
|
@ -44,13 +44,14 @@ safelog = { path = "../safelog", version = "0.3.1" }
|
|||
slotmap = "1.0.6"
|
||||
strum = { version = "0.24", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
tor-bytes = { path = "../tor-bytes", version = "0.7.1" }
|
||||
tor-checkable = { path = "../tor-checkable", version = "0.5.1" }
|
||||
tor-circmgr = { version = "0.9.0", path = "../tor-circmgr", features = ["hs-client"] }
|
||||
tor-config = { path = "../tor-config", version = "0.9.1" }
|
||||
tor-dirclient = { path = "../tor-dirclient", version = "0.7.1", default-features = false, features = ["hs-client"] }
|
||||
tor-error = { path = "../tor-error", version = "0.5.1", features = ["experimental-api"] } # TODO HS
|
||||
tor-hscrypto = { version = "0.2.1", path = "../tor-hscrypto" }
|
||||
tor-linkspec = { version = "0.8.0", path = "../tor-linkspec" }
|
||||
tor-linkspec = { version = "0.8.0", path = "../tor-linkspec", features = ["decode", "verbatim"] }
|
||||
tor-llcrypto = { version = "0.5.1", path = "../tor-llcrypto" }
|
||||
tor-netdir = { version = "0.9.1", path = "../tor-netdir", features = ["hs-client"] }
|
||||
tor-netdoc = { path = "../tor-netdoc", version = "0.8.0", features = ["hs-client"] }
|
||||
|
|
|
@ -42,6 +42,7 @@ mod connect;
|
|||
mod err;
|
||||
mod isol_map;
|
||||
mod keys;
|
||||
mod relay_info;
|
||||
mod state;
|
||||
|
||||
use std::future::Future;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
//! Translate relay information from the formats used in the onion service
|
||||
//! protocol into `CircTarget`s that we can use for building circuits.
|
||||
//!
|
||||
//! (Later this will include support for INTRODUCE2 messages too.)
|
||||
|
||||
#![allow(dead_code, unreachable_pub)] // TODO HS remove these once this API is exposed.
|
||||
|
||||
use tor_error::into_internal;
|
||||
use tor_linkspec::{
|
||||
decode::Strictness, verbatim::VerbatimLinkSpecCircTarget, CircTarget, EncodedLinkSpec,
|
||||
OwnedChanTargetBuilder, OwnedCircTarget,
|
||||
};
|
||||
use tor_llcrypto::pk::curve25519;
|
||||
use tor_netdir::NetDir;
|
||||
use tor_netdoc::doc::hsdesc::IntroPointDesc;
|
||||
|
||||
/// Helper: create a [`CircTarget`] from its component parts as provided by
|
||||
/// another party on the network.
|
||||
///
|
||||
/// This function is used to build a `CircTarget` from an `IntroPointDesc` (for
|
||||
/// extending to an introduction point). Later, it can also be used to build a
|
||||
/// CircTarget from an `Introduce2` message (for extending to a rendezvous
|
||||
/// point).
|
||||
fn circtarget_from_pieces(
|
||||
linkspecs: &[EncodedLinkSpec],
|
||||
ntor_onion_key: &curve25519::PublicKey,
|
||||
netdir: &NetDir,
|
||||
) -> Result<impl CircTarget, InvalidTarget> {
|
||||
let mut bld = OwnedCircTarget::builder();
|
||||
// Decode the link specifiers and use them to find out what we can about
|
||||
// this relay.
|
||||
let linkspecs_decoded = linkspecs
|
||||
.iter()
|
||||
.map(|ls| ls.parse())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
*bld.chan_target() =
|
||||
OwnedChanTargetBuilder::from_linkspecs(Strictness::Standard, &linkspecs_decoded[..])?;
|
||||
// Look up the relay in the directory, to see:
|
||||
// 1) if it is flatly impossible,
|
||||
// 2) what subprotocols we should assume it implements.
|
||||
let protocols = {
|
||||
let chan_target = bld.chan_target().build().map_err(into_internal!(
|
||||
"from_linkspecs gave us a non-working ChanTargetBuilder"
|
||||
))?;
|
||||
match netdir.by_ids_detailed(&chan_target)? {
|
||||
Some(relay) => relay.protovers().clone(),
|
||||
None => netdir.relay_protocol_status().required_protocols().clone(),
|
||||
}
|
||||
};
|
||||
bld.protocols(protocols);
|
||||
bld.ntor_onion_key(*ntor_onion_key);
|
||||
let circ_target = bld.build().map_err(into_internal!(
|
||||
"somehow we made an invalid CircTargetBuilder"
|
||||
))?;
|
||||
Ok(VerbatimLinkSpecCircTarget::new(
|
||||
circ_target,
|
||||
linkspecs.to_vec(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Construct a [`CircTarget`] from a provided [`IntroPointDesc`].
|
||||
///
|
||||
/// Onion service clients use this function to convert an `IntroPointDesc` in
|
||||
/// the onion service descriptor into a form that they can use when building a
|
||||
/// circuit to an introduction point.
|
||||
///
|
||||
/// The `netdir` argument is used to fill in missing information about the
|
||||
/// target relay, and to make sure that the target relay's identities are not
|
||||
/// inconsistent with the rest of the network.
|
||||
pub(crate) fn ipt_to_circtarget(
|
||||
desc: &IntroPointDesc,
|
||||
netdir: &NetDir,
|
||||
) -> Result<impl CircTarget, InvalidTarget> {
|
||||
circtarget_from_pieces(desc.link_specifiers(), desc.ipt_ntor_key(), netdir)
|
||||
}
|
||||
|
||||
/// We were given unusable information about an introduction point or rendezvous
|
||||
/// point.
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum InvalidTarget {
|
||||
/// The provided link specifiers included some that, when we tried to parse
|
||||
/// them, proved to be misformed.
|
||||
#[error("Misformed channel target information provided")]
|
||||
UnparseableChanTargetInfo(#[from] tor_bytes::Error),
|
||||
|
||||
/// The provided link specifiers were inconsistent with one another, or missing
|
||||
/// key information.
|
||||
#[error("Invalid channel target information provided")]
|
||||
InvalidChanTargetInfo(#[from] tor_linkspec::decode::ChanTargetDecodeError),
|
||||
|
||||
/// The provided relay identities (in the link specifiers) described a relay
|
||||
/// which, according to the network directory, cannot possibly exist.
|
||||
#[error("Impossible combination of relay identities")]
|
||||
ImpossibleRelayIds(#[from] tor_netdir::RelayLookupError),
|
||||
|
||||
/// An internal error occurred.
|
||||
#[error("{0}")]
|
||||
Bug(#[from] tor_error::Bug),
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
ADDED: Accessor for relay protocol status.
|
||||
|
|
@ -1081,6 +1081,25 @@ impl NetDir {
|
|||
pub fn params(&self) -> &NetParameters {
|
||||
&self.params
|
||||
}
|
||||
|
||||
/// Return a [`ProtoStatus`](netstatus::ProtoStatus) that lists the
|
||||
/// network's current requirements and recommendations for the list of
|
||||
/// protocols that every relay must implement.
|
||||
//
|
||||
// TODO HS: I am not sure this is the right API; other alternatives would be:
|
||||
// * To expose the _required_ relay protocol list instead (since that's all that
|
||||
// onion service implementations need).
|
||||
// * To expose the client protocol list as well (for symmetry).
|
||||
// * To expose the MdConsensus instead (since that's more general, although
|
||||
// it restricts the future evolution of this API).
|
||||
//
|
||||
// I think that this is a reasonably good compromise for now, but I'm going
|
||||
// to put it behind the `hs-common` feature to give us time to consider more.
|
||||
#[cfg(feature = "hs-common")]
|
||||
pub fn relay_protocol_status(&self) -> &netstatus::ProtoStatus {
|
||||
self.consensus.relay_protocol_status()
|
||||
}
|
||||
|
||||
/// Return weighted the fraction of relays we can use. We only
|
||||
/// consider relays that match the predicate `usable`. We weight
|
||||
/// this bandwidth according to the provided `role`.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ADDED: accessors for protocol status.
|
||||
|
|
@ -201,6 +201,8 @@ where
|
|||
}
|
||||
|
||||
/// A list of subprotocol versions that implementors should/must provide.
|
||||
///
|
||||
/// Each consensus has two of these: one for relays, and one for clients.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ProtoStatus {
|
||||
|
@ -679,6 +681,18 @@ impl<RS> Consensus<RS> {
|
|||
pub fn shared_rand_prev(&self) -> Option<&SharedRandStatus> {
|
||||
self.header.shared_rand_prev.as_ref()
|
||||
}
|
||||
|
||||
/// Return a [`ProtoStatus`] that lists the network's current requirements and
|
||||
/// recommendations for the list of protocols that every relay must implement.
|
||||
pub fn relay_protocol_status(&self) -> &ProtoStatus {
|
||||
&self.header.hdr.relay_protos
|
||||
}
|
||||
|
||||
/// Return a [`ProtoStatus`] that lists the network's current requirements and
|
||||
/// recommendations for the list of protocols that every client must implement.
|
||||
pub fn client_protocol_status(&self) -> &ProtoStatus {
|
||||
&self.header.hdr.client_protos
|
||||
}
|
||||
}
|
||||
|
||||
decl_keyword! {
|
||||
|
@ -895,6 +909,24 @@ impl ProtoStatus {
|
|||
required,
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the protocols that are listed as "required" in this `ProtoStatus`.
|
||||
///
|
||||
/// Implementations may assume that relays on the network implement all the
|
||||
/// protocols in the relays' required-protocols list. Implementations should
|
||||
/// refuse to start if they do not implement all the protocols on their own
|
||||
/// (client or relay) required-protocols list.
|
||||
pub fn required_protocols(&self) -> &Protocols {
|
||||
&self.required
|
||||
}
|
||||
|
||||
/// Return the protocols that are listed as "recommended" in this `ProtoStatus`.
|
||||
///
|
||||
/// Implementations should warn if they do not implement all the protocols
|
||||
/// on their own (client or relay) recommended-protocols list.
|
||||
pub fn recommended_protocols(&self) -> &Protocols {
|
||||
&self.recommended
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::str::FromStr for NetParams<T>
|
||||
|
|
Loading…
Reference in New Issue