Skip to main content

tor_hsclient/
relay_info.rs

1//! Translate relay information from the formats used in the onion service
2//! protocol into `CircTarget`s that we can use for building circuits.
3//!
4//! (Later this will include support for INTRODUCE2 messages too.)
5
6use tor_error::{HasRetryTime, RetryTime};
7use tor_linkspec::CircTarget;
8use tor_netdir::NetDir;
9use tor_netdoc::doc::hsdesc::IntroPointDesc;
10
11/// Construct a [`CircTarget`] from a provided [`IntroPointDesc`].
12///
13/// Onion service clients use this function to convert an `IntroPointDesc` in
14/// the onion service descriptor into a form that they can use when building a
15/// circuit to an introduction point.
16///
17/// The `netdir` argument is used to fill in missing information about the
18/// target relay, and to make sure that the target relay's identities are not
19/// inconsistent with the rest of the network.
20pub(crate) fn ipt_to_circtarget(
21    desc: &IntroPointDesc,
22    netdir: &NetDir,
23) -> Result<impl CircTarget + use<>, InvalidTarget> {
24    Ok(netdir.circ_target_from_verbatim_linkspecs(desc.link_specifiers(), desc.ipt_ntor_key())?)
25}
26
27/// We were given unusable information about an introduction point or rendezvous
28/// point.
29//
30// This is returned by `ipt_to_circtarget`.  It will also be used for rendezvous
31// points when we implement the HS server side.
32// At that point, this module will need to move to a crate where it can be used
33// by the HS server code.
34#[derive(Clone, Debug, thiserror::Error)]
35#[non_exhaustive]
36pub enum InvalidTarget {
37    /// The provided link specifiers included some that, when we tried to parse
38    /// them, proved to be malformed.
39    #[error("Malformed channel target information provided")]
40    UnparseableChanTargetInfo(#[from] tor_bytes::Error),
41
42    /// We couldn't build a proper introduction point from the provided link specifiers.
43    #[error("Unable to reconstruct introduction point")]
44    InvalidIntroPoint(#[from] tor_netdir::VerbatimCircTargetDecodeError),
45
46    /// An internal error occurred.
47    #[error("{0}")]
48    Bug(#[from] tor_error::Bug),
49}
50
51/// When to maybe retry *with the same inputs* that generated this error.
52///
53/// When returned from `ipt_to_circtarget`, that means this is when to retry
54/// the *same introduction point* for the *same hidden service*.
55///
56/// "The same introduction point" means one with precisely the same set of identities
57/// and link specifiers.
58//
59// Note about correctness, and introduction point identity:
60//
61// We use this as part of HasRetryTime for FailedAttemptError.
62// HasRetryTime for FailedAttemptError is used for selecting which intro point to retry.
63// Our introduction point experiences are recorded according to *one* relay identity,
64// not the complete set.
65//
66// Nevertheless, this is correct, because: we only select from, and record experiences for,
67// *usable* introduction points.  An InvalidTarget error is detected early enough
68// to avoid regarding the introduction point as usable at all.  So we never use
69// this RetryTime impl, here, to choose between introduction points.
70impl HasRetryTime for InvalidTarget {
71    fn retry_time(&self) -> RetryTime {
72        use InvalidTarget as IT;
73        use RetryTime as RT;
74        match self {
75            IT::UnparseableChanTargetInfo(..) => RT::Never,
76            IT::InvalidIntroPoint(..) => RT::Never,
77            IT::Bug(..) => RT::Never,
78        }
79    }
80}