tor_dircommon/
fallback.rs1use base64ct::{Base64Unpadded, Encoding as _};
14use derive_deftly::Deftly;
15use tor_config::derive::prelude::*;
16use tor_config::{ConfigBuildError, define_list_builder_accessors, define_list_builder_helper};
17use tor_llcrypto::pk::ed25519::Ed25519Identity;
18use tor_llcrypto::pk::rsa::RsaIdentity;
19
20use std::net::SocketAddr;
21
22#[derive(Debug, Clone, Deftly, Eq, PartialEq)]
30#[derive_deftly(TorConfig)]
31#[deftly(tor_config(
32 no_default_trait,
33 post_build = "FallbackDirBuilder::post_build_validate"
34))]
35pub struct FallbackDir {
36 #[deftly(tor_config(no_default))]
38 rsa_identity: RsaIdentity,
39 #[deftly(tor_config(no_default))]
41 ed_identity: Ed25519Identity,
42 #[deftly(tor_config(no_magic, setter(skip), no_default))]
47 orports: Vec<SocketAddr>,
48}
49
50define_list_builder_accessors!(
51 struct FallbackDirBuilder {
52 pub orports: [SocketAddr],
53 }
54);
55
56impl FallbackDirBuilder {
57 fn post_build_validate(built: FallbackDir) -> Result<FallbackDir, ConfigBuildError> {
59 if built.orports.is_empty() {
60 return Err(ConfigBuildError::Invalid {
61 field: "orport".to_string(),
62 problem: "list was empty".to_string(),
63 });
64 }
65 Ok(built)
66 }
67}
68
69#[derive(Debug, Clone, Default, PartialEq, Eq)]
75pub struct FallbackList {
76 fallbacks: Vec<FallbackDir>,
78}
79
80impl<T: IntoIterator<Item = FallbackDir>> From<T> for FallbackList {
81 fn from(fallbacks: T) -> Self {
82 FallbackList {
83 fallbacks: fallbacks.into_iter().collect(),
84 }
85 }
86}
87
88define_list_builder_helper! {
89 pub struct FallbackListBuilder {
91 pub(crate) fallbacks: [FallbackDirBuilder],
92 }
93 built: FallbackList = FallbackList { fallbacks };
94 default = default_fallbacks();
95}
96
97impl FallbackList {
98 pub fn len(&self) -> usize {
100 self.fallbacks.len()
101 }
102 pub fn is_empty(&self) -> bool {
104 self.fallbacks.is_empty()
105 }
106 pub fn iter(&self) -> std::slice::Iter<'_, FallbackDir> {
108 self.fallbacks.iter()
109 }
110}
111
112pub(crate) fn default_fallbacks() -> Vec<FallbackDirBuilder> {
115 fn fallback(rsa: &str, ed: &str, ports: &[&str]) -> FallbackDirBuilder {
117 let rsa = RsaIdentity::from_hex(rsa).expect("Bad hex in built-in fallback list");
118 let ed = Base64Unpadded::decode_vec(ed).expect("Bad hex in built-in fallback list");
119 let ed = Ed25519Identity::from_bytes(&ed).expect("Wrong length in built-in fallback list");
120 let mut bld = FallbackDir::builder();
121 bld.rsa_identity(rsa).ed_identity(ed);
122
123 ports
124 .iter()
125 .map(|s| s.parse().expect("Bad socket address in fallbacklist"))
126 .for_each(|p| {
127 bld.orports().push(p);
128 });
129
130 bld
131 }
132 include!("../data/fallback_dirs.rs")
133}
134
135impl tor_linkspec::HasAddrs for FallbackDir {
136 fn addrs(&self) -> impl Iterator<Item = SocketAddr> {
137 self.orports.iter().copied()
138 }
139}
140impl tor_linkspec::HasRelayIdsLegacy for FallbackDir {
141 fn ed_identity(&self) -> &Ed25519Identity {
142 &self.ed_identity
143 }
144 fn rsa_identity(&self) -> &RsaIdentity {
145 &self.rsa_identity
146 }
147}
148
149impl tor_linkspec::DirectChanMethodsHelper for FallbackDir {}
150
151impl tor_linkspec::ChanTarget for FallbackDir {}