tor_guardmgr/
fallback.rs

1//! List of directories that ships with Tor, for initial directory
2//! operations.
3//!
4//! When a client doesn't have directory information yet, it uses a
5//! "Fallback Directory" to retrieve its initial information about the
6//! network.
7//!
8//! # Semver note
9//!
10//! The types in this module are re-exported from `arti-client` and
11//! `tor-dirmgr`: any changes here must be reflected there.
12
13mod set;
14
15use base64ct::{Base64Unpadded, Encoding as _};
16use derive_builder::Builder;
17use tor_config::ConfigBuildError;
18use tor_config::{define_list_builder_accessors, impl_standard_builder, list_builder::VecBuilder};
19use tor_linkspec::{DirectChanMethodsHelper, OwnedChanTarget};
20use tor_llcrypto::pk::ed25519::Ed25519Identity;
21use tor_llcrypto::pk::rsa::RsaIdentity;
22
23use serde::{Deserialize, Serialize};
24use std::net::SocketAddr;
25
26use crate::dirstatus::DirStatus;
27pub(crate) use set::FallbackState;
28pub use set::{FallbackList, FallbackListBuilder};
29
30/// A directory whose location ships with Tor (or arti), and which we
31/// can use for bootstrapping when we don't know anything else about
32/// the network.
33//
34// Note that we do *not* set serde(deny_unknown_fields) on this
35// structure: we want our fallback directory configuration format to
36// be future-proof against adding new info about each fallback.
37#[derive(Debug, Clone, Builder, Eq, PartialEq)]
38#[builder(build_fn(private, name = "build_unvalidated", error = "ConfigBuildError"))]
39#[builder(derive(Debug, Serialize, Deserialize))]
40pub struct FallbackDir {
41    /// RSA identity for the directory relay
42    rsa_identity: RsaIdentity,
43    /// Ed25519 identity for the directory relay
44    ed_identity: Ed25519Identity,
45    /// List of ORPorts for the directory relay
46    #[builder(sub_builder(fn_name = "build"), setter(custom))]
47    orports: Vec<SocketAddr>,
48}
49
50impl_standard_builder! { FallbackDir: !Default }
51
52define_list_builder_accessors! {
53    struct FallbackDirBuilder {
54        pub orports: [SocketAddr],
55    }
56}
57
58impl FallbackDir {
59    /// Return a copy of this FallbackDir as a [`FirstHop`](crate::FirstHop)
60    pub fn as_guard(&self) -> crate::FirstHop {
61        crate::FirstHop {
62            sample: None,
63            inner: crate::FirstHopInner::Chan(OwnedChanTarget::from_chan_target(self)),
64        }
65    }
66}
67
68impl FallbackDirBuilder {
69    /// Make a new FallbackDirBuilder.
70    ///
71    /// You only need to use this if you're using a non-default set of
72    /// fallback directories.
73    pub fn new() -> Self {
74        Self::default()
75    }
76    /// Builds a new `FallbackDir`.
77    ///
78    /// ### Errors
79    ///
80    /// Errors unless both of `rsa_identity`, `ed_identity`, and at least one `orport`,
81    /// have been provided.
82    pub fn build(&self) -> std::result::Result<FallbackDir, ConfigBuildError> {
83        let built = self.build_unvalidated()?;
84        if built.orports.is_empty() {
85            return Err(ConfigBuildError::Invalid {
86                field: "orport".to_string(),
87                problem: "list was empty".to_string(),
88            });
89        }
90        Ok(built)
91    }
92}
93
94/// Return a list of the default fallback directories shipped with
95/// arti.
96pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
97    /// Build a fallback directory; panic if input is bad.
98    fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
99        let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
100        let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
101        let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
102        let mut bld = FallbackDir::builder();
103        bld.rsa_identity(rsa).ed_identity(ed);
104
105        ports
106            .iter()
107            .map(|s| s.parse().expect("Bad socket address in fallbacklist"))
108            .for_each(|p| {
109                bld.orports().push(p);
110            });
111
112        bld
113    }
114    include!("../data/fallback_dirs.rs")
115}
116
117impl tor_linkspec::HasAddrs for FallbackDir {
118    fn addrs(&self) -> &[SocketAddr] {
119        &self.orports[..]
120    }
121}
122impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
123    fn ed_identity(&self) -> &Ed25519Identity {
124        &self.ed_identity
125    }
126    fn rsa_identity(&self) -> &RsaIdentity {
127        &self.rsa_identity
128    }
129}
130
131impl DirectChanMethodsHelper for FallbackDir {}
132
133impl tor_linkspec::ChanTarget for FallbackDir {}