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

            
13
mod set;
14

            
15
use base64ct::{Base64Unpadded, Encoding as _};
16
use derive_builder::Builder;
17
use tor_config::ConfigBuildError;
18
use tor_config::{define_list_builder_accessors, impl_standard_builder, list_builder::VecBuilder};
19
use tor_linkspec::{DirectChanMethodsHelper, OwnedChanTarget};
20
use tor_llcrypto::pk::ed25519::Ed25519Identity;
21
use tor_llcrypto::pk::rsa::RsaIdentity;
22

            
23
use serde::{Deserialize, Serialize};
24
use std::net::SocketAddr;
25

            
26
use crate::dirstatus::DirStatus;
27
pub(crate) use set::FallbackState;
28
pub 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
2985420
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
38
#[builder(build_fn(private, name = "build_unvalidated", error = "ConfigBuildError"))]
39
#[builder(derive(Debug, Serialize, Deserialize))]
40
pub 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

            
50
impl_standard_builder! { FallbackDir: !Default }
51

            
52
define_list_builder_accessors! {
53
    struct FallbackDirBuilder {
54
        pub orports: [SocketAddr],
55
    }
56
}
57

            
58
impl 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

            
68
impl 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
746314
    pub fn build(&self) -> std::result::Result<FallbackDir, ConfigBuildError> {
83
746314
        let built = self.build_unvalidated()?;
84
746314
        if built.orports.is_empty() {
85
            return Err(ConfigBuildError::Invalid {
86
                field: "orport".to_string(),
87
                problem: "list was empty".to_string(),
88
            });
89
746314
        }
90
746314
        Ok(built)
91
746314
    }
92
}
93

            
94
/// Return a list of the default fallback directories shipped with
95
/// arti.
96
3731
pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
97
    /// Build a fallback directory; panic if input is bad.
98
746200
    fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
99
746200
        let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
100
746200
        let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
101
746200
        let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
102
746200
        let mut bld = FallbackDir::builder();
103
746200
        bld.rsa_identity(rsa).ed_identity(ed);
104
746200

            
105
746200
        ports
106
746200
            .iter()
107
1133769
            .map(|s| s.parse().expect("Bad socket address in fallbacklist"))
108
1133769
            .for_each(|p| {
109
1115569
                bld.orports().push(p);
110
1133769
            });
111
746200

            
112
746200
        bld
113
746200
    }
114
    include!("../data/fallback_dirs.rs")
115
3731
}
116

            
117
impl tor_linkspec::HasAddrs for FallbackDir {
118
    fn addrs(&self) -> &[SocketAddr] {
119
        &self.orports[..]
120
    }
121
}
122
impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
123
773766
    fn ed_identity(&self) -> &Ed25519Identity {
124
773766
        &self.ed_identity
125
773766
    }
126
34346
    fn rsa_identity(&self) -> &RsaIdentity {
127
34346
        &self.rsa_identity
128
34346
    }
129
}
130

            
131
impl DirectChanMethodsHelper for FallbackDir {}
132

            
133
impl tor_linkspec::ChanTarget for FallbackDir {}